76 Commits

Author SHA1 Message Date
peterlu14 0b56283b43 -temp change fixed range 2023-08-31 15:23:43 +08:00
peterlu14 62e849671d - change text style
- change tumor size
- fixed empty data error
- fixed shapes & annotation refresh problem
- fixed only one marker color problem
- change x-axis dtick
2023-08-31 15:23:12 +08:00
peterlu14 240e18868a -update custom data 2023-08-30 09:58:54 +08:00
peterlu14 bafa2b1b87 -update chart style & text & color 2023-08-30 09:56:53 +08:00
peterlu14 08109f4e2d -update subject page with new UI and function 2023-08-24 16:09:16 +08:00
peterlu14 40e1f82af0 -fix avatar resouce
-add tumor size display
2023-06-14 17:09:41 +08:00
peterlu14 0305407949 - update subject page 2023-06-05 14:07:27 +08:00
peterlu14 a1e1dd0c72 - fix EIS channel select wrong 2023-04-28 10:26:48 +08:00
peterlu14 556fd0697f - fix reset
- update find with range
2023-04-27 11:56:51 +08:00
peterlu14 47f5da9efc - disable zoom in when max min boundry is given
- file info add working mode & date
- filter size 0 data
- format code
2023-03-23 12:53:38 +08:00
peterlu14 9bf9db5263 - add right click context menu 2023-03-20 17:40:34 +08:00
peterlu14 8070da4270 - echarts series sampling with lttb
- echarts add color support
- support line in batch mode
- create canvas class
- add find meta files api
- auto import boundry from interactive mode
2023-03-17 17:09:16 +08:00
peterlu14 e666d75772 - support time channel
- support none filter mode
2023-03-14 10:36:57 +08:00
peterlu14 4507ee1c35 - file loading 2 second
- default channel [1,2]
2023-03-07 17:44:49 +08:00
peterlu14 6537664c04 - let to const 2023-03-07 16:48:30 +08:00
peterlu14 ab2b3b2fa4 -remove import defineExpose & defineEmit 2023-03-07 16:47:22 +08:00
peterlu14 8c6f551a35 -remove useless files 2023-03-07 16:41:43 +08:00
peterlu14 3c835eec6a - upgrade modules in package.json (-ionicons) 2023-03-07 16:30:15 +08:00
peterlu14 c3570d1259 - add canvas class and store
- add data-analysis store to save batchMode
- channel store to save generate x & y axis
- data-analysis page display can be switch to display chart
2023-03-06 17:17:41 +08:00
peterlu14 1230a5ffa6 [update] remove useless sidebar 2023-03-02 15:22:57 +08:00
peterlu14 2fd179b73d -file slider loading
-change message format
-disable console
-add console time
-callback func data format change
-remove time limit
-grid show remove
2023-02-13 09:59:42 +08:00
peterlu14 feeb423e24 - get file data onMounted 2023-02-04 18:01:43 +08:00
peterlu14 a1c202fc5c - add chartAPI to series markLine formatter
- rename XAxis & YAxis class
2023-02-04 18:01:03 +08:00
peterlu14 1a5bcf0a58 - chart reset function to fix series not render problem 2023-02-04 15:57:03 +08:00
peterlu14 6b7e5015e7 - let series & markLine tooltip follow unit & scale 2023-02-04 15:55:33 +08:00
peterlu14 d2ccfc63a4 - chart grid height 80% to 75% 2023-02-03 18:27:12 +08:00
peterlu14 c94d4360e6 -add yAxisManager setting in click start button
-replace x-axis setting with axis-setting can both use by x&y axis
-remove chart watch select files
2023-02-03 18:23:25 +08:00
peterlu14 62f62ef5e5 [update] add y-axis manager 2023-02-03 17:02:39 +08:00
peterlu14 aadbb6c482 [update] legend locate bottom & x-axis default name remove 2023-02-03 16:50:10 +08:00
peterlu14 69dc2a718f [update] x-axis fixed & interval follow the unit 2023-02-03 16:49:11 +08:00
peterlu14 4fc46ca4ea [update] x-axis change unit 2023-02-03 15:04:25 +08:00
peterlu14 840f0af14b [update] chart build timing from select file to press start button 2023-02-03 11:07:58 +08:00
peterlu14 53d131376d [update] add Grid & tooltip 2023-02-03 10:12:54 +08:00
peterlu14 f83f8eb8f8 [update] folder rename 2023-02-03 10:10:05 +08:00
peterlu14 68356fbd04 [update] add xAxisManager & giveup setOption & appendData api 2023-02-02 11:20:07 +08:00
peterlu14 a357102e82 [update] restruct again 2023-02-01 11:19:57 +08:00
peterlu14 6ac8e8cd4a [update] resturct data-analysis files struct 2023-02-01 11:16:06 +08:00
peterlu14 3cbc572592 test 2023-01-31 17:50:28 +08:00
peterlu14 ef8ce2a0c4 [update] add chart series 2023-01-31 10:37:06 +08:00
peterlu14 9000fabdea [update] chart init & series data api init 2023-01-18 17:29:48 +08:00
peterlu14 06afc2e1a3 [update] fix render problem 2023-01-13 11:51:25 +08:00
peterlu14 3dfef28777 [update] filetable update 2023-01-12 17:37:54 +08:00
peterlu14 4d48e82997 [update] add new slideout & table 2023-01-12 16:06:51 +08:00
peterlu14 5af4215562 Merge remote-tracking branch 'origin/10-test' into dev/file_modal 2023-01-06 13:41:44 +08:00
peterlu14 4f94fcf541 [update] temp get all files 2023-01-06 13:40:59 +08:00
peterlu14 22afbab8ff [update] fix vue-router deploy apache problem 2023-01-06 13:40:16 +08:00
lai8928 ef22f1d20b [update]button link 2023-01-06 13:05:52 +08:00
peterlu14 99f401bac0 [update] router default page direct to data-analysis 2023-01-06 11:13:42 +08:00
peterlu14 3d751f746b [debug] temp fix typescript error 2023-01-06 11:12:49 +08:00
peterlu14 2df4ccf13c [update] fix channel 2023-01-06 10:42:20 +08:00
lai8928 0786113589 Merge remote-tracking branch 'origin/dev/file_modal' into 10-test 2023-01-04 10:19:33 +08:00
lai8928 7499f34dc7 change controller id 2023-01-04 10:17:52 +08:00
peterlu14 a65fea33a9 [update] change control panel to script setup & fix style error 2023-01-04 10:15:11 +08:00
peterlu14 90ba4b448a Merge remote-tracking branch 'origin/10-test' into dev/file_modal 2023-01-03 17:33:42 +08:00
lai8928 dfb3a96f84 [update] merge file modal 2023-01-03 16:50:40 +08:00
lai8928 58eecd80ae Merge remote-tracking branch 'origin/dev/file_modal' into 10-test 2022-12-30 15:58:27 +08:00
peterlu14 ec29b2fbc7 [update] show info 2022-12-30 15:20:11 +08:00
peterlu14 b8a7b39b62 [update] pass fileview-select & channel by create pinia store 2022-12-30 15:17:43 +08:00
peterlu14 4e041645a8 [update] channel X & Y select and emit 2022-12-30 09:53:35 +08:00
peterlu14 5fe5a64140 [update] import config table 2022-12-30 09:51:23 +08:00
peterlu14 746f4d98ec [update] restruct Device type & add getMetaFile 2022-12-30 09:48:47 +08:00
lai8928 4e8254e2d7 add csv download test 2022-12-29 14:09:05 +08:00
peterlu14 7043581335 [update] change-note 2022-12-29 11:42:35 +08:00
peterlu14 a0d8020787 [update] reformat file.ts & fileModal 2022-12-29 11:41:28 +08:00
peterlu14 6144b60541 [update] update change-note 2022-12-29 10:52:44 +08:00
peterlu14 42f5a37e4d [update] build file system for data analysis 2022-12-29 10:49:19 +08:00
lai8928 a9c59953f4 [fix] package.json lint command error 2022-12-09 11:12:30 +08:00
lai8928 93badd5ecf add mode input form 2022-12-09 11:09:13 +08:00
peterlu14 2b4f9bb90c [update] concat data from callback to charts & start button emit 2022-12-06 15:32:22 +08:00
peterlu14 63d0b4d79a [update] add chart api setOption & appendData & markLine & Loading 2022-12-06 14:13:02 +08:00
peterlu14 d7675c0b6a [update] add markLineComponent 2022-12-06 14:11:00 +08:00
peterlu14 1fc202c785 [update] add chart structure 2022-12-06 14:10:18 +08:00
peterlu14 804d95d493 [update] add line chart 2022-12-01 11:52:04 +08:00
peterlu14 8925bbe343 [update] add mqtt method publish & unique client_id 2022-12-01 10:33:19 +08:00
peterlu14 a64f0d93da [update] create new page data analysis 2022-12-01 09:56:15 +08:00
peterlu14 ac3b303b2e [update] import mqtt & echarts 2022-12-01 09:54:55 +08:00
255 changed files with 20390 additions and 16800 deletions
+1
View File
@@ -22,6 +22,7 @@ module.exports = {
], ],
rules: { rules: {
'@typescript-eslint/no-empty-interface': 0,
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'prettier/prettier': ['warn', {}, { usePrettierrc: true }], 'prettier/prettier': ['warn', {}, { usePrettierrc: true }],
+16
View File
@@ -0,0 +1,16 @@
### 2022.12.30
- file system
### 2022.12.06
- e-chart
- mqtt
- new page data-analysis
### 2022.11.30
- setup environment
- vite config add path
- import windicss
- add vue-shim.d.ts file (TS2307)
+3 -2
View File
@@ -1,11 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" class="bg-red-500"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> <!-- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" /> -->
<!-- <script src="https://cdn.plot.ly/plotly-2.20.0.min.js" charset="utf-8"></script> -->
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<title>Vuestic Admin</title> <title>Vuestic Admin</title>
+4322 -1032
View File
File diff suppressed because it is too large Load Diff
+49 -39
View File
@@ -8,7 +8,7 @@
"build": "npm run lint && vue-tsc --noEmit && vite build", "build": "npm run lint && vue-tsc --noEmit && vite build",
"build:ci": "vite build", "build:ci": "vite build",
"prelint": "npm run format", "prelint": "npm run format",
"lint": "eslint --fix './src/**/*.{ts,js,vue}'", "lint": "eslint --fix \"./src/**/*.{ts,js,vue}\"",
"format": "prettier --write .", "format": "prettier --write .",
"preview": "vite preview" "preview": "vite preview"
}, },
@@ -18,52 +18,62 @@
] ]
}, },
"dependencies": { "dependencies": {
"@amcharts/amcharts5": "^5.2.19", "@amcharts/amcharts5": "^5.3.6",
"@amcharts/amcharts5-geodata": "^5.0.3", "@amcharts/amcharts5-geodata": "^5.1.0",
"@fortawesome/fontawesome-free": "^6.1.1", "@fortawesome/fontawesome-free": "^6.3.0",
"@gtm-support/vue-gtm": "^1.6.0", "@gtm-support/vue-gtm": "^2.0.0",
"axios": "^0.27.2", "@hyjiacan/vue-slideout": "^3.0.2",
"chart.js": "^3.8.0", "axios": "^1.3.4",
"chart.js": "^4.2.1",
"epic-spinners": "^2.0.0", "epic-spinners": "^2.0.0",
"flag-icons": "^6.6.4", "flag-icons": "^6.6.6",
"ionicons": "^4.6.3", "ionicons": "^4.6.3",
"leaflet": "^1.8.0", "leaflet": "^1.9.3",
"leaflet-map": "^0.2.1", "leaflet-map": "^0.2.1",
"maplibre-gl": "^2.1.9", "maplibre-gl": "^2.4.0",
"material-icons": "^1.13.7",
"medium-editor": "^5.23.3", "medium-editor": "^5.23.3",
"pinia": "^2.0.16", "npm-check-updates": "^16.7.10",
"register-service-worker": "^1.7.1", "pinia": "^2.0.33",
"sass": "^1.53.0", "plotly.js-dist-min": "^2.23.2",
"vue": "^3.2.25", "register-service-worker": "^1.7.2",
"vue-chartjs": "^4.1.1", "sass": "^1.58.3",
"vue-i18n": "^9.1.10", "v-contextmenu": "^3.0.0",
"vue-router": "^4.0.14", "vue": "^3.2.47",
"vue-chartjs": "^5.2.0",
"vue-good-table-next": "^0.2.1",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6",
"vue-yandex-maps": "^0.12.3", "vue-yandex-maps": "^0.12.3",
"vuestic-ui": "^1.5.0" "vuestic-ui": "^1.6.1"
}, },
"devDependencies": { "devDependencies": {
"@intlify/vite-plugin-vue-i18n": "^5.0.1", "@intlify/vite-plugin-vue-i18n": "^6.0.3",
"@types/leaflet": "^1.7.11", "@types/leaflet": "^1.9.1",
"@types/medium-editor": "^5.0.5", "@types/medium-editor": "^5.0.5",
"@types/node": "^17.0.25", "@types/node": "^18.14.6",
"@typescript-eslint/eslint-plugin": "^5.20.0", "@typescript-eslint/eslint-plugin": "^5.54.1",
"@typescript-eslint/parser": "^5.20.0", "@typescript-eslint/parser": "^5.54.1",
"@vitejs/plugin-vue": "^2.3.3", "@vitejs/plugin-vue": "^4.0.0",
"@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^10.0.0", "@vue/eslint-config-typescript": "^11.0.2",
"autoprefixer": "^10.4.4", "autoprefixer": "^10.4.13",
"eslint": "^8.13.0", "echarts": "^5.4.1",
"eslint-plugin-prettier": "^4.0.0", "eslint": "^8.35.0",
"eslint-plugin-vue": "^8.7.0", "eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.1", "eslint-plugin-vue": "^9.9.0",
"lint-staged": "^13.0.1", "husky": "^8.0.3",
"postcss": "^8.4.12", "lint-staged": "^13.1.2",
"prettier": "^2.6.2", "mqtt": "^4.3.7",
"typescript": "^4.5.4", "postcss": "^8.4.21",
"vite": "^2.9.9", "prettier": "^2.8.4",
"vite-plugin-windicss": "^1.8.8", "typescript": "^4.9.5",
"vue-eslint-parser": "^8.3.0", "unocss": "^0.51.12",
"vue-tsc": "^1.0.10", "vite": "^4.1.4",
"vite-plugin-windicss": "^1.8.10",
"vue-echarts": "^6.5.4",
"vue-eslint-parser": "^9.1.0",
"vue-tsc": "^1.2.0",
"windicss": "^3.5.6" "windicss": "^3.5.6"
} }
} }
+6205
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -14,5 +14,6 @@
body { body {
margin: 0; margin: 0;
background: white;
} }
</style> </style>
+12
View File
@@ -0,0 +1,12 @@
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1765_7055)">
<path d="M0 0H512V512H0V0Z" fill="#222D3A"/>
<path d="M330.085 110.955C311.299 90.672 285.059 79.5024 256.097 79.5024C226.981 79.5024 200.655 90.6044 181.955 110.762C163.053 131.141 153.843 158.838 156.005 188.746C160.292 247.751 205.192 295.75 256.097 295.75C307.003 295.75 351.826 247.76 356.18 188.765C358.371 159.128 349.103 131.489 330.085 110.955Z" fill="#B3BAC0"/>
<path d="M53.9275 511.997H458.333C459 503 458.206 483.499 456.333 473.141C448.185 427.941 422.757 389.972 382.789 363.327C347.282 339.675 302.305 326.642 256.13 326.642C209.956 326.642 164.978 339.666 129.471 363.327C89.5038 389.982 64.0754 427.951 55.9275 473.15C54.0546 483.509 53.5001 504.5 53.9275 511.997Z" fill="#B3BAC0"/>
</g>
<defs>
<clipPath id="clip0_1765_7055">
<rect width="512" height="512" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 956 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

+8
View File
@@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_56_271" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<rect width="24" height="24" fill="#D9D9D9"/>
</mask>
<g mask="url(#mask0_56_271)">
<path d="M7 21C6.45 21 5.97917 20.8042 5.5875 20.4125C5.19583 20.0208 5 19.55 5 19V6H4V4H9V3H15V4H20V6H19V19C19 19.55 18.8042 20.0208 18.4125 20.4125C18.0208 20.8042 17.55 21 17 21H7ZM17 6H7V19H17V6ZM9 17H11V8H9V17ZM13 17H15V8H13V17Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

+8
View File
@@ -0,0 +1,8 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_52_158" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="24" height="24">
<rect width="24" height="24" fill="#D9D9D9"/>
</mask>
<g mask="url(#mask0_52_158)">
<path d="M19.5 11V13.5H18.5V11V10.5H18H15.5V9.5H18H18.5V9V6.5H19.5V9V9.5H20H22.5V10.5H20H19.5V11ZM2.5 18V18.5H3H15H15.5V18V17.2C15.5 16.9288 15.4309 16.6712 15.2891 16.4393C15.1536 16.2175 14.9702 16.0392 14.7428 15.9129L14.7333 15.9076L14.7236 15.9028C13.7925 15.4372 12.8493 15.0863 11.8942 14.8519C10.939 14.6174 9.97395 14.5 9 14.5C8.02605 14.5 7.06104 14.6174 6.10581 14.8519C5.15072 15.0863 4.20748 15.4372 3.27639 15.9028L3.26668 15.9076L3.25718 15.9129C3.0298 16.0392 2.84639 16.2175 2.71086 16.4393C2.56911 16.6712 2.5 16.9288 2.5 17.2V18ZM9 11.5C8.03366 11.5 7.21887 11.1618 6.52855 10.4714C5.83824 9.78113 5.5 8.96634 5.5 8C5.5 7.03366 5.83824 6.21887 6.52855 5.52855C7.21887 4.83824 8.03366 4.5 9 4.5C9.96634 4.5 10.7811 4.83824 11.4714 5.52855C12.1618 6.21887 12.5 7.03366 12.5 8C12.5 8.96634 12.1618 9.78113 11.4714 10.4714C10.7811 11.1618 9.96634 11.5 9 11.5ZM1.5 19.5V17.2C1.5 16.7241 1.62109 16.2941 1.86359 15.8991C2.10825 15.5007 2.42772 15.2027 2.82681 14.9956C3.82714 14.4957 4.84065 14.1222 5.86769 13.8735C6.89573 13.6245 7.93956 13.5 9 13.5C10.0604 13.5 11.1043 13.6245 12.1323 13.8735C13.1594 14.1222 14.1729 14.4957 15.1732 14.9956C15.5723 15.2027 15.8918 15.5007 16.1364 15.8991C16.3789 16.2941 16.5 16.7241 16.5 17.2V19.5H1.5ZM9 10.5C9.68366 10.5 10.2814 10.2507 10.7661 9.76605C11.2507 9.28137 11.5 8.68366 11.5 8C11.5 7.31634 11.2507 6.71863 10.7661 6.23395C10.2814 5.74926 9.68366 5.5 9 5.5C8.31634 5.5 7.71863 5.74926 7.23395 6.23395C6.74926 6.71863 6.5 7.31634 6.5 8C6.5 8.68366 6.74926 9.28137 7.23395 9.76605C7.71863 10.2507 8.31634 10.5 9 10.5Z" fill="#424242" stroke="#424242"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,196 @@
<template>
<div>
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div>
<p>Unit ({{ unitObj.text }})</p>
</div>
<va-button-toggle
v-model="unitObj.text"
:options="unitOption"
@update:model-value="changeUnit"
></va-button-toggle>
</div>
<va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div class="col-span-1">
<p>Space</p>
</div>
<va-input
v-model="leftBoundryInput"
:label="axis === 'x' ? 'Left' : 'Bottom'"
placeholder="10%"
class="col-span-2"
@keyup.enter="setBoundry"
@blur="setBoundry"
/>
<va-input
v-model="rightBoundryInput"
:label="axis === 'x' ? 'Right' : 'Top'"
placeholder="10%"
class="px-1 col-span-2"
@keyup.enter="setBoundry"
@blur="setBoundry"
/>
<div class="mx-2 col-span-1 justify-self-end">
<button @click="resetBoundry">Reset</button>
</div>
</div>
<va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div class="col-span-1">
<p>Fixed</p>
</div>
<va-input
v-model="minInput"
class="col-span-2"
label="Min"
@keyup.enter="setMin(minInput)"
@blur="setMin(minInput)"
>
<template #appendInner>{{ unitObj.text }}</template>
</va-input>
<va-input
v-model="maxInput"
class="px-1 col-span-2"
label="Max"
@keyup.enter="setMax(maxInput)"
@blur="setMax(maxInput)"
>
<template #appendInner>{{ unitObj.text }}</template>
</va-input>
<div class="mx-2 col-span-1 justify-self-end">
<button small @click="resetMinMax">Reset</button>
</div>
</div>
<va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div>
<p>Interval</p>
</div>
<va-input
v-model="intervalInput"
class="col-span-2"
@keyup.enter="setInterval(Number(intervalInput))"
@blur="setInterval(Number(intervalInput))"
>
<template #appendInner>{{ unitObj.text }}</template>
</va-input>
<div class="mx-2 col-span-3 justify-self-end">
<button small @click="resetInterval">Reset</button>
</div>
</div>
<!-- <va-divider />
<div class="mt-2 mx-1 grid grid-cols-6 items-center">
<div>
<p>SplitLine</p>
</div>
<va-counter v-model="splitNumber" class="col-span-2" @update:model-value="setSplitNumber" />
</div> -->
</div>
<va-divider />
</template>
<script setup lang="ts">
import { ref, computed, toRef, defineProps } from 'vue'
import { XAxisManager } from '@/utils/chart/x-axis/xAxisManager'
import { YAxisManager } from '@/utils/chart/y-axis/yAxisManager'
/* init definition */
const props = defineProps<{
axis: string
axisManager: XAxisManager | YAxisManager
axisIndex: number
dataZoom: object
}>()
const axisManager = toRef(props, 'axisManager')
const dataZoom = toRef(props, 'dataZoom')
/** axis setting */
/* unit */
const unitObj = computed(() => axisManager.value.getUnit())
const unitOption = computed(() =>
Object.keys(unitObj.value.option).map((ele) => {
return { label: ele, value: ele }
}),
)
const changeUnit = function (_unit: string) {
/* caculate the ratio */
const oldScale = unitObj.value.scale
const newScale = unitObj.value.option[_unit]
const ratio = newScale / oldScale
/* correct the input value with ratio */
if (maxInput.value !== '') maxInput.value = String(Number(maxInput.value) / ratio)
if (minInput.value !== '') minInput.value = String(Number(minInput.value) / ratio)
if (intervalInput.value !== '') intervalInput.value = String(Number(intervalInput.value) / ratio)
/* change the scale */
unitObj.value.scale = unitObj.value.option[_unit]
}
/* boundry */
const leftBoundryInput = ref('')
const rightBoundryInput = ref('')
const setBoundry = function () {
if (leftBoundryInput.value === '') leftBoundryInput.value = '0'
if (rightBoundryInput.value === '') rightBoundryInput.value = '0'
axisManager.value.setBoundry([leftBoundryInput.value, rightBoundryInput.value])
dataZoom.value[0].disabled = true
}
const resetBoundry = function () {
leftBoundryInput.value = ''
rightBoundryInput.value = ''
axisManager.value.resetBoundry()
dataZoom.value[0].disabled = false
}
/* max & min */
const maxInput = ref('')
const minInput = ref('')
const setMax = function (max: string) {
if (max === '') return
/* adjust max with scale */
max = String(Number(max) * unitObj.value.scale)
/* set max */
axisManager.value.setMax(max)
dataZoom.value[0].disabled = true
}
const setMin = function (min: string) {
if (min === '') return
/* adjust min with scale */
min = String(Number(min) * unitObj.value.scale)
/* set min */
axisManager.value.setMin(min)
dataZoom.value[0].disabled = true
}
const resetMinMax = function () {
maxInput.value = ''
minInput.value = ''
axisManager.value.resetMinMax()
dataZoom.value[0].disabled = false
}
/* interval */
const intervalInput = ref('')
const setInterval = function (interval: number) {
if (interval <= 0) return
interval = Number(interval) * unitObj.value.scale
axisManager.value.setInterval(interval)
}
const resetInterval = function () {
intervalInput.value = ''
axisManager.value.resetInterval()
}
/* splitLine */
const splitNumber = ref(5)
const setSplitNumber = function (splitNumber: number) {
axisManager.value.setSplitNumber(splitNumber)
}
</script>
<style></style>
@@ -0,0 +1,46 @@
<template>
<slideout v-model="show" :show-mask="false" :arrow-button="false" :title="title" :size="'30%'" dock="left" resizable>
<div class="grid justify-items-center self-center text-lg">
<span>X-Axis</span>
</div>
<va-divider />
<AxisSetting
axis="x"
:axis-manager="chartStore.chartManager.children[chartIndex].xAxisManager"
:data-zoom="chartStore.chartManager.children[chartIndex].dataZoom"
:axis-index="0"
></AxisSetting>
<div class="grid justify-items-center self-center text-lg">
<span>Y-Axis</span>
</div>
<va-divider />
<AxisSetting
axis="y"
:axis-manager="chartStore.chartManager.children[chartIndex].yAxisManager"
:data-zoom="chartStore.chartManager.children[chartIndex].dataZoom"
:axis-index="0"
></AxisSetting>
</slideout>
</template>
<script setup lang="ts">
import AxisSetting from './AxisSetting.vue'
import { ref, computed } from 'vue'
import { useChartStore } from '@/stores/data-analysis/chart'
const title = 'Axis Settings'
const chartStore = useChartStore()
const chartIndex = ref(0)
/* slideout show */
const show = computed({
// getter
get() {
return chartStore.xAxisSlider
},
// setter
set(newValue) {
chartStore.xAxisSlider = newValue
},
})
</script>
@@ -0,0 +1,428 @@
<template>
<div class="">
<v-contextmenu ref="contextmenu">
<v-contextmenu-item @click="changeAxisPointer">pointer</v-contextmenu-item>
<v-contextmenu-item v-if="canvasInstance.format === 'line'" @click="changeFormat('scatter')"
>scatter</v-contextmenu-item
>
<v-contextmenu-item v-if="canvasInstance.format === 'scatter'" @click="changeFormat('line')"
>line</v-contextmenu-item
>
<v-contextmenu-item @click="deleteSelected">clear</v-contextmenu-item>
<v-contextmenu-item @click="download">download</v-contextmenu-item>
</v-contextmenu>
<va-card v-contextmenu:contextmenu class="h-full">
<va-card-content class="h-full">
<div style="position: relative" class="h-full">
<canvas
id="lineCanvas"
class="myCanvas"
:width="width"
:height="height"
style="position: absolute; top: 0; left: 0"
></canvas>
<canvas
id="scatterCanvas"
class="myCanvas displayNone"
:width="width"
:height="height"
style="position: absolute; top: 0; left: 0"
></canvas>
<canvas
id="axisCanvas"
class="myCanvas"
:width="width"
:height="height"
style="position: absolute; top: 0; left: 0"
></canvas>
</div>
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed, onMounted } from 'vue'
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import api from '@/data/server-api'
import { useToast } from 'vuestic-ui'
const { init } = useToast()
const canvasStore = useCanvasStore()
const { width, height, numTicks, innerWidth, innerHeight, start, end, xTickPixels, yTickPixels, x, y } =
canvasStore.canvas
// monitor screen height
const screenHeight = computed(() => canvasStore.canvas.screenHeight)
// monitor screen width
const screenWidth = computed(() => canvasStore.canvas.screenWidth)
// monitor screen inner height
const screenInnerHeight = computed(() => canvasStore.canvas.screenInnerHeight)
// monitor screen inner width
const screenInnerWidth = computed(() => canvasStore.canvas.screenInnerWidth)
// line or scatter
const format = computed(() => canvasStore.canvas.format)
// canvas instance
const canvasInstance = canvasStore.canvas
// show axis pointer
const showAxisPointer = ref(false)
let axisCanvas: HTMLCanvasElement
let axisCtx: CanvasRenderingContext2D
let lineCanvas: HTMLCanvasElement
let lineCtx: CanvasRenderingContext2D
let scatterCanvas: HTMLCanvasElement
let scatterCtx: CanvasRenderingContext2D
// show axis pointer or not
const changeAxisPointer = function () {
showAxisPointer.value = !showAxisPointer.value
reDraw()
}
// change line or scatter
const changeFormat = function (format: string) {
canvasInstance.format = format
}
// delect select rect
const deleteSelected = function () {
canvasInstance.resetSelected()
reDraw()
}
const download = function () {
// create combined canvas
const combinedCanvas = document.createElement('canvas')
const combinedCtx = combinedCanvas.getContext('2d')
// if the source canvas is exist
if (combinedCtx && lineCanvas && scatterCanvas) {
// define height & width
combinedCanvas.width = axisCanvas.width
combinedCanvas.height = axisCanvas.height
// make background white
combinedCtx.fillStyle = '#FFFFFF'
combinedCtx.fillRect(0, 0, combinedCanvas.width, combinedCanvas.height)
// draw axis
combinedCtx.drawImage(axisCanvas, 0, 0)
combinedCtx.globalCompositeOperation = 'multiply'
// draw line
if (format.value === 'line') combinedCtx.drawImage(lineCanvas, 0, 0)
// draw scatter
if (format.value === 'scatter') combinedCtx.drawImage(scatterCanvas, 0, 0)
// create download link
const link = document.createElement('a')
link.download = 'canvas.png'
link.href = combinedCanvas.toDataURL()
link.click()
}
}
// mouse down position
let mouseStartX = -1
let mouseStartY = -1
// mouse moving temp position
let mouseTempX = -1
let mouseTempY = -1
// mouse up position
let mouseEndX = -1
let mouseEndY = -1
// dragging flag
let isDragging = false
// color code
let colorIndex = 0
const generatorColor = function () {
const colorCode = [
'#054A91',
'#5FA8D3',
'#16697A',
'#2A9D8F',
'#746C68',
'#E9C46A',
'#F78514',
'#D14958',
'#4C4DC8',
'#9E2A2B',
'#F87575',
]
const ret = colorCode[colorIndex]
colorIndex = colorIndex === colorCode.length ? 0 : colorIndex + 1
return ret
}
const calcPositionX = function (xPos: number) {
const diffX = xPos - x.range[0]
let ratioX = Math.abs(diffX / (x.range[1] - x.range[0]))
if (ratioX > 1) ratioX = 1
return Math.trunc(ratioX * innerWidth) + start.x
}
const calcPositionY = function (yPoint: number) {
const diffY = y.range[1] - yPoint
let ratioY = Math.abs(diffY / (y.range[1] - y.range[0]))
if (ratioY > 1) ratioY = 1
return Math.trunc(ratioY * innerHeight) + end.y
}
const drawPoint = function (posX: number, posY: number, color: string, ctx: CanvasRenderingContext2D) {
// draw circle & fill color
ctx.beginPath()
ctx.arc(posX, posY, 2, 0, 2 * Math.PI)
ctx.fillStyle = color
ctx.fill()
}
// Helper function to draw the x axis with tick marks
function drawXAxis(xMin: number, xMax: number, tickPixels: number[], ctx: CanvasRenderingContext2D) {
// draw axis line
ctx.beginPath()
ctx.moveTo(start.x, start.y)
ctx.lineTo(end.x, start.y)
ctx.fillStyle = 'black'
ctx.lineWidth = 1
ctx.font = '40px sans-serif'
ctx.textAlign = 'center'
// draw axis tickle
for (let i = 0; i < tickPixels.length; i++) {
const x = tickPixels[i]
ctx.moveTo(start.x + x, start.y)
ctx.lineTo(start.x + x, start.y + 15)
const text = canvasInstance.getXText(xMin + (i / numTicks) * (xMax - xMin))
ctx.fillText(text, start.x + x, start.y + 75)
}
ctx.strokeStyle = 'black'
ctx.stroke()
}
function drawYAxis(yMin: number, yMax: number, tickPixels: number[], ctx: CanvasRenderingContext2D) {
// draw axis line
ctx.beginPath()
ctx.moveTo(start.x, start.y)
ctx.lineTo(start.x, end.y)
ctx.fillStyle = 'black'
ctx.font = '40px sans-serif'
ctx.textAlign = 'right'
ctx.lineWidth = 1
// draw axis tickle
for (let i = 0; i < tickPixels.length; i++) {
const y = tickPixels[i]
ctx.moveTo(start.x, start.y - y)
ctx.lineTo(start.x - 25, start.y - y)
const text = canvasInstance.getYText(yMin + (i / numTicks) * (yMax - yMin))
ctx.fillText(text, start.x - 30, start.y - y + 15)
}
ctx.strokeStyle = 'black'
ctx.stroke()
}
const drawXAxisPointer = function (mouseX: number, ctx: CanvasRenderingContext2D) {
const x = (mouseX * width) / screenWidth.value
ctx.moveTo(x, start.y)
ctx.lineTo(x, end.y)
ctx.strokeStyle = 'black'
ctx.stroke()
const value = canvasInstance.mouseXToValue(mouseX)
const text = canvasInstance.getXText(value)
ctx.textAlign = 'center'
ctx.fillText(text, x, start.y + 50)
}
const drawYAxisPointer = function (mouseY: number, ctx: CanvasRenderingContext2D) {
const y = (mouseY * height) / screenHeight.value
ctx.moveTo(start.x, y)
ctx.lineTo(end.x, y)
ctx.strokeStyle = 'black'
ctx.stroke()
const value = canvasInstance.mouseYToValue(mouseY)
const text = canvasInstance.getYText(value)
ctx.textAlign = 'right'
ctx.fillText(text, start.x, y)
}
const drawInputData = function (x: string | any[], y: number[]) {
const color = generatorColor()
// draw line
lineCtx.beginPath()
lineCtx.moveTo(calcPositionX(x[0]), calcPositionY(y[0]))
for (let i = 0; i < x.length; i++) {
const X = calcPositionX(x[i])
const Y = calcPositionY(y[i])
lineCtx.lineTo(X, Y)
// draw point
drawPoint(X, Y, color, scatterCtx)
}
lineCtx.lineWidth = 2
lineCtx.strokeStyle = color
lineCtx.stroke()
}
const generateAxis = function () {
drawXAxis(Number(x.range[0]), Number(x.range[1]), xTickPixels, axisCtx)
drawYAxis(Number(y.range[0]), Number(y.range[1]), yTickPixels, axisCtx)
}
const resetCanvas = function () {
axisCtx.clearRect(0, 0, width, height)
lineCtx?.clearRect(0, 0, width, height)
scatterCtx?.clearRect(0, 0, width, height)
}
const outOfBoundry = function (mouseX: number, mouseY: number) {
if (mouseX < canvasInstance.getBoundryInScreen(3) || mouseX > canvasInstance.getBoundryInScreen(1)) return true
if (mouseY < canvasInstance.getBoundryInScreen(0) || mouseY > canvasInstance.getBoundryInScreen(2)) return true
return false
}
const reDraw = function () {
const rect = axisCanvas.getBoundingClientRect()
// Clear the canvas
axisCtx.clearRect(0, 0, width, height)
// Draw the x and y axes with tick marks
generateAxis()
// Draw the x and y axis pointers
if (showAxisPointer.value === true) {
drawXAxisPointer(mouseTempX, axisCtx)
drawYAxisPointer(mouseTempY, axisCtx)
}
for (const selectionRect of canvasInstance.selectedSave) {
axisCtx.lineWidth = 5
axisCtx.strokeRect(
(selectionRect[0] / rect.width) * width,
(selectionRect[1] / rect.height) * height,
((selectionRect[2] - selectionRect[0]) / rect.width) * width,
((selectionRect[3] - selectionRect[1]) / rect.height) * height,
)
}
if (isDragging || (mouseEndX !== -1 && mouseEndY !== -1)) {
if (isDragging === true) {
mouseEndX = mouseTempX
mouseEndY = mouseTempY
}
axisCtx.lineWidth = 5
axisCtx.strokeRect(
(mouseStartX / rect.width) * width,
(mouseStartY / rect.height) * height,
((mouseEndX - mouseStartX) / rect.width) * width,
((mouseEndY - mouseStartY) / rect.height) * height,
)
}
}
onMounted(() => {
axisCanvas = document.getElementById('axisCanvas') as HTMLCanvasElement
axisCtx = axisCanvas?.getContext('2d')
lineCanvas = document.getElementById('lineCanvas') as HTMLCanvasElement
lineCtx = lineCanvas?.getContext('2d')
scatterCanvas = document.getElementById('scatterCanvas') as HTMLCanvasElement
scatterCtx = scatterCanvas?.getContext('2d')
const rect = axisCanvas?.getBoundingClientRect()
if (rect) {
canvasInstance.setScreenSize(rect.width, rect.height)
}
// resize
window.addEventListener('resize', () => {
const rect = axisCanvas?.getBoundingClientRect()
if (rect) canvasInstance.setScreenSize(rect.width, rect.height)
})
// listen for mouse down event
axisCanvas?.addEventListener('mousedown', (event) => {
if (event.button === 0) {
const rect = axisCanvas.getBoundingClientRect()
// reset mouse up
mouseEndX = -1
mouseEndY = -1
// set starting coordinates of square
mouseStartX = event.clientX - rect.left
mouseStartY = event.clientY - rect.top
if (outOfBoundry(mouseStartX, mouseStartY) === true) return
isDragging = true
}
})
// listen for mouse up event
axisCanvas?.addEventListener('mouseup', async () => {
const rect = axisCanvas.getBoundingClientRect()
if (mouseEndX === -1 || mouseEndY === -1) return
canvasInstance.selectedSave.push([mouseStartX, mouseStartY, mouseEndX, mouseEndY])
// update ending coordinates of square
const dataStartX =
((mouseStartX - rect.width * 0.1) * (x.range[1] - x.range[0])) / screenInnerWidth.value + Number(x.range[0])
const dataEndX =
((mouseEndX - rect.width * 0.1) * (x.range[1] - x.range[0])) / screenInnerWidth.value + Number(x.range[0])
const dataStartY =
((rect.height - mouseStartY - rect.height * 0.1) * (y.range[1] - y.range[0])) / screenInnerHeight.value +
Number(y.range[0])
const dataEndY =
((rect.height - mouseEndY - rect.height * 0.1) * (y.range[1] - y.range[0])) / screenInnerHeight.value +
Number(y.range[0])
const xInfo = [canvasInstance.x.channel.id, dataStartX, dataEndX]
const yInfo = [canvasInstance.y.channel.id, dataStartY, dataEndY]
const ret = await api.meta.findMeta(canvasStore.canvas.metaIds, [xInfo, yInfo])
console.log('ret', ret)
for (const mes of ret.data) {
init(mes[1])
}
// reset mouse position
mouseStartX = mouseStartY = mouseEndX = mouseEndY = -1
// reset isDraggable flag
isDragging = false
})
axisCanvas?.addEventListener('mousemove', function (event) {
const rect = axisCanvas.getBoundingClientRect()
// get mouse current pos
mouseTempX = event.clientX - rect.left
mouseTempY = event.clientY - rect.top
if (outOfBoundry(mouseTempX, mouseTempY) === true) return
reDraw()
})
})
watch(format, (newVal: string) => {
if (newVal === 'line') {
lineCanvas?.classList.remove('displayNone')
scatterCanvas?.classList.add('displayNone')
}
if (newVal === 'scatter') {
lineCanvas?.classList.add('displayNone')
scatterCanvas?.classList.remove('displayNone')
}
})
defineExpose({ reDraw, generateAxis, drawInputData, resetCanvas })
</script>
<style>
.myCanvas {
width: 100%;
height: 100%;
}
.displayNone {
display: none;
}
</style>
@@ -0,0 +1,106 @@
<template>
<div>
<va-card class="h-full">
<va-card-content class="h-full w-full">
<EChart ref="chart_ref" :option="chart" :autoresize="true" :loading="loading" />
</va-card-content>
</va-card>
<AxisSettingSlider></AxisSettingSlider>
</div>
</template>
<script setup lang="ts">
import { ECharts, EChartsCoreOption } from 'echarts'
import { ref, onMounted } from 'vue'
import { useChartStore } from '@/stores/data-analysis/chart'
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import AxisSettingSlider from './AxisSettingSlider.vue'
import Chart from '@/utils/chart/chart'
const chartStore = useChartStore()
const canvasStore = useCanvasStore()
const chartIndex = 0
interface Props {
chart: Chart
}
const props = defineProps<Props>()
const chart_ref = ref<ECharts | null>(null)
const setOption = function (option: EChartsCoreOption, notMerge = false) {
chart_ref.value?.setOption(option, notMerge)
}
const appendData = function (seriesIndex: number, data: Array<number | string>) {
if (data.length <= 5e4) {
chartStore.chartManager.children[chartIndex].series[seriesIndex].data.push(...data)
} else {
for (const _data of data) {
chartStore.chartManager.children[chartIndex].series[seriesIndex].data.push(_data)
}
}
// chart_ref.value?.appendData({
// seriesIndex: seriesIndex,
// data: data,
// })
// chart_ref.value?.resize()
setTimeout(() => {
const chartXRange = chart_ref.value.chart.getModel().getComponent('xAxis').axis.scale._extent
const chartYRange = chart_ref.value.chart.getModel().getComponent('yAxis').axis.scale._extent
canvasStore.canvas.x.range = chartXRange.map((val: number) => String(val))
canvasStore.canvas.y.range = chartYRange.map((val: number) => String(val))
})
}
const markLine = function (value: number | Array<number> | string, seriesIndex = 0) {
chartStore.chartManager.children[chartIndex].series[seriesIndex].markLine.data = value
// chart_ref.value?.setOption({
// series: [
// {
// markLine: {
// data: [{ name: header, yAxis: value }],
// },
// },
// ],
// })
}
/* refresh */
const reset = function () {
setOption({}, true)
}
/* Loading */
const loading = ref(false)
const startLoading = function () {
loading.value = true
}
const stopLoading = function () {
loading.value = false
}
onMounted(() => {
const newTool = {
show: true,
title: 'custom icon1',
icon: 'path://M432.45,595.444c0,2.177-4.661,6.82-11.305,6.82c-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M421.146,591.891c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479,423.062,591.891,421.146,591.891L421.146,591.891zM421.146,591.891',
onclick: function () {
chartStore.xAxisSlider = !chartStore.xAxisSlider
},
}
for (const chart of chartStore.chartManager.children) {
chart.toolbox.feature['myTool1'] = newTool
}
})
defineExpose({
startLoading,
stopLoading,
setOption,
appendData,
markLine,
reset,
})
</script>
<style lang=""></style>
@@ -0,0 +1,54 @@
<template>
<div>
<div>
X-Axis
<va-select
v-model="channelStore.xAxisSelected"
:text-by="'name'"
:options="xOption"
:no-options-text="'Select a file first.'"
></va-select>
</div>
<div>
Y-Axis
<va-select
v-model="channelStore.yAxisSelected"
:text-by="'name'"
:options="yOption"
:no-options-text="'Select a file first.'"
></va-select>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, watch } from 'vue'
import { useChannelStore } from '@/stores/data-analysis/channel'
const channelStore = useChannelStore()
const xOption = computed(() => channelStore.xAxisOptions)
const yOption = computed(() => channelStore.yAxisOptions)
watch(
xOption,
() => {
if (Object.keys(channelStore.xAxisSelected).length === 0) {
channelStore.xAxisSelected = xOption.value[1]
}
},
{
deep: true,
},
)
watch(
yOption,
() => {
if (Object.keys(channelStore.yAxisSelected).length === 0) {
channelStore.yAxisSelected = yOption.value[2]
}
},
{
deep: true,
},
)
</script>
@@ -0,0 +1,44 @@
<template>
<va-card>
<va-card-content>
<va-button @click="showModal">FILE</va-button>
<p>X: {{ channelStore.xAxisSelected.name }} Y: {{ channelStore.yAxisSelected.name }}</p>
<va-list class="py-2" fit>
<va-list-label> </va-list-label>
<template v-for="(file, i) in selectedFiles" :key="'item' + file.id">
<va-list-item>
<va-list-item-section>
<va-list-item-label>
{{ file.name }}
</va-list-item-label>
</va-list-item-section>
</va-list-item>
<va-list-separator v-if="i < selectedFiles.length - 1" :key="'separator' + i" class="my-1" fit />
</template>
</va-list>
<Suspense>
<FileSlide ref="file_modal_ref"></FileSlide>
</Suspense>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import FileSlide from './FileSlider.vue'
const channelStore = useChannelStore()
const fileViewStore = useFileViewStore()
const selectedFiles = reactive(fileViewStore.selectedFiles)
/* File Modal Handling */
const file_modal_ref = ref<InstanceType<typeof FileSlide> | null>(null)
const showModal = function () {
file_modal_ref.value?.showModal()
}
defineExpose({ file_modal_ref, showModal })
</script>
@@ -0,0 +1,147 @@
<template>
<slideout v-model="showSlideOut" title="The title" :size="'120%'" dock="left" resizable>
<ChannelSelector></ChannelSelector>
<div class="pa-1 d-flex align-center">
<va-button-group class="mr-1">
<va-button @click="changeViewFormat(0)">Table</va-button>
<va-button disabled @click="changeViewFormat(1)">Tree</va-button>
</va-button-group>
<va-button-group class="mr-3">
<va-button @click="changeFileView('time')">Time</va-button>
<va-button @click="changeFileView('folder')">Folder</va-button>
<va-button @click="changeFileView('project')">Project</va-button>
</va-button-group>
<va-button-group>
<va-button @click="expandAll(true)">Expand</va-button>
<va-button @click="expandAll(false)">Close</va-button>
</va-button-group>
</div>
<va-inner-loading :loading="loading">
<div>
<TableFormat
v-if="viewFormat === 0"
ref="table_format_ref"
:columns="columns"
:rows="rows"
@on-select="onSelect"
></TableFormat>
<TreeFormat v-if="viewFormat === 1" ref="table_format_ref" :columns="columns" :rows="rows"></TreeFormat>
</div>
</va-inner-loading>
</slideout>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import { useChannelStore } from '@/stores/data-analysis/channel'
import { MetaFile } from '@/utils/file'
import TableFormat from './TableFormat.vue'
import TreeFormat from './TreeFormat.vue'
import ChannelSelector from './ChannelSelector.vue'
import configTable from '@/data/config-table'
const table_format_ref = ref<InstanceType<typeof TableFormat> | null>(null)
const getWorkingMode = function (rowObj) {
if (rowObj.parameter) return configTable.getModeConfig(rowObj.parameter._LIBRARY_, rowObj.parameter.MODE).name
return
}
const getDate = function (rowObj) {
if (rowObj.created_at) {
return rowObj.created_at.replace('Z', '').replace('T', ' ')
}
return
}
const fileViewStore = useFileViewStore()
const channelStore = useChannelStore()
const fileView = reactive(fileViewStore.fileView)
const rows: any = fileView.children
const columns = reactive([
{
label: 'Name',
field: 'name',
},
{
label: 'Working Mode',
field: getWorkingMode,
},
{
label: 'TotalTime',
field: 'time',
type: 'number',
},
{
label: 'Size',
field: 'size',
type: 'number',
},
{
label: 'Created At',
field: getDate,
},
])
const loading = ref(true)
const showSlideOut = ref(false)
const showModal = function () {
showSlideOut.value = !showSlideOut.value
setTimeout(() => {
loading.value = false
}, 2000)
}
const viewFormat = ref(0)
const changeViewFormat = function (view: number) {
viewFormat.value = view
}
const changeFileView = async function (view: string) {
loading.value = true
fileView.changeView(view)
await fileView.appendChildren(1)
loading.value = false
}
const expandAll = function (expandOrNot: boolean) {
if (expandOrNot === true) table_format_ref.value?.expandAll()
if (expandOrNot === false) table_format_ref.value?.collapseAll()
}
const onSelect = function (selectedFile: MetaFile[]) {
fileViewStore.selectedFiles.length = 0
fileViewStore.selectedFiles.push(...selectedFile)
if (fileViewStore.selectedFiles.length > 0) {
// TODO get all selected library
const config: any = configTable.getModeConfig(
fileViewStore.selectedFiles[0].device.library_name,
fileViewStore.selectedFiles[0].parameter.MODE,
)
const channelKey = Object.keys(config.channels)
const channel = Object.values(config.channels)
const channelOptions = channel.map((v: any, idx) => {
v.id = channelKey[idx]
if (v.name === 'Time') {
v.id = 'Time'
}
return v
})
channelStore.xAxisOptions.length = 0
channelStore.xAxisOptions.push(...channelOptions)
channelStore.yAxisOptions.length = 0
channelStore.yAxisOptions.push(...channelOptions)
}
}
onMounted(() => {
fileView.appendChildren()
})
defineExpose({
showModal,
})
</script>
<style lang="scss"></style>
@@ -0,0 +1,64 @@
<template>
<VueGoodTable
ref="vue_good_table_refs"
:columns="columns"
:rows="rows"
:select-options="{ enabled: true, selectAllByGroup: true }"
:search-options="{ enabled: true }"
:group-options="{
enabled: true,
collapsable: true,
rowKey: 'id',
}"
@selected-rows-change="select"
>
</VueGoodTable>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { MetaFile } from '@/utils/file'
// emit
const emit = defineEmits(['onSelect'])
// props
defineProps({
columns: {
type: Array,
default: () => {
return []
},
},
rows: {
type: Array,
default: () => {
return []
},
},
})
// ref
const vue_good_table_refs = ref()
const expandAll = function () {
vue_good_table_refs.value.expandAll()
}
const collapseAll = function () {
vue_good_table_refs.value.collapseAll()
}
const select = function (params: { selectedRows: MetaFile[] }) {
emit('onSelect', params.selectedRows)
}
onMounted(() => {
// Due to "vue_good_table" package error, need to fix group select by reassign function
vue_good_table_refs.value.toggleSelectGroup = function (event: { checked: any }, headerRow: { children: any[] }) {
headerRow.children.forEach((row: { [x: string]: any }) => {
row['vgtSelected'] = event.checked
})
}
})
defineExpose({ expandAll, collapseAll })
</script>
<style></style>
@@ -0,0 +1,55 @@
<template>
<va-tree-view
v-model:checked="selectedNodes"
v-model:expanded="expanedNodes"
:nodes="rows"
class="customizable-content"
:filter="filter"
:filter-method="customFilterMethod"
:track-by="'idType'"
:value-by="'idType'"
selectable
>
<template #content="node">
<div class="align-center">
<va-icon v-if="node.type === 'Folder' && node.expanded === false" class="fas fa-folder mr-2" />
<va-icon v-if="node.type === 'Folder' && node.expanded === true" class="fas fa-folder-open mr-2" />
<va-icon v-if="node.type === 'MetaFile'" class="fas fa-file mr-2" />
<template v-if="node.type !== 'MetaFile'">{{ node.name }}</template>
<template v-if="node.type === 'MetaFile'">
{{ node.name }}
</template>
</div>
</template>
</va-tree-view>
</template>
<script setup lang="ts">
import { Ref, ref, computed } from 'vue'
defineProps({
columns: {
type: Array,
default: () => {
return []
},
},
rows: {
type: Array,
default: () => {
return []
},
},
})
const filter = ref('')
const selectedNodes: Ref<(never | string)[]> = ref([])
const expanedNodes: Ref<(never | string)[]> = ref([])
// filter function
const customFilterMethod = computed(() => {
return (node: any, filterText: string) => {
// console.log('customFilterMethod', node, filterText, key, node.name.includes(filterText))
return node.name.includes(filterText)
}
})
</script>
@@ -0,0 +1,178 @@
<template>
<div>
<va-card class="h-full">
<va-card-content>
<va-switch
v-model="daSettingStore.batchMode"
class="mb-1"
size="small"
true-label="Batch Mode"
false-label="InterActive Mode"
></va-switch>
<va-select
v-model="simpleSelectModel"
class="my-1"
:label="'Filter Mode'"
text-by="description"
track-by="id"
:options="simpleOptions"
/>
<div class="my-2">
<div v-if="simpleSelectModel.id === 1">
<va-slider v-model="VTModeModel" label="percentage(%)" track-label-visible :min="0" :max="50" />
</div>
<div v-else-if="simpleSelectModel.id === 2">
<va-slider v-model="slopModeModel" label="1D window" track-label-visible :min="1" :max="50" />
</div>
<div v-else></div>
</div>
<div v-if="daSettingStore.batchMode" class="my-2">
<va-switch
v-model="lineOrScatter"
class="mb-1"
size="small"
true-label="Scatter"
false-label="Line"
></va-switch>
<div>
<h1>Fixed Boundry</h1>
<va-divider></va-divider>
<div class="my-1 grid grid-cols-12 items-center">
<span>x</span>
<va-input v-model="canvasStore.canvas.x.range[0]" class="col-span-5">
<template #appendInner> </template>
</va-input>
<br />
<va-input v-model="canvasStore.canvas.x.range[1]" class="col-span-5"></va-input>
</div>
<div class="my-1 grid grid-cols-12 items-center">
<span>y</span>
<va-input v-model="canvasStore.canvas.y.range[0]" class="col-span-5"></va-input>
<br />
<va-input v-model="canvasStore.canvas.y.range[1]" class="col-span-5"></va-input>
</div>
</div>
</div>
<div>
<va-button class="mt-2" @click="filterData">Start</va-button>
</div>
</va-card-content>
</va-card>
</div>
</template>
<script setup lang="ts">
import { useChannelStore } from '@/stores/data-analysis/channel'
import { useChartStore } from '@/stores/data-analysis/chart'
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import { useDASettingStore } from '@/stores/data-analysis/data-analysis'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import { Ref, ref, computed } from 'vue'
const emit = defineEmits(['filter-data'])
// chart index
const chartIndex = 0
// create stores
const chartStore = useChartStore()
const channelStore = useChannelStore()
const fileView = useFileViewStore()
const canvasStore = useCanvasStore()
const daSettingStore = useDASettingStore()
// setting
const VTModeModel = ref(10)
const slopModeModel = ref(20)
const simpleOptions = ref([
{ id: 0, description: 'None' },
{
id: 1,
description: 'V-T Mode',
},
{
id: 2,
description: '1st Order Differential',
},
{
id: 3,
description: 'Third option',
},
])
const simpleSelectModel: Ref<{ id: number; description: string }> = ref(simpleOptions.value[0])
const lineOrScatter = ref(false)
// const xOption = computed(() => channelStore.xAxisOptions)
// const yOption = computed(() => channelStore.yAxisOptions)
/* Start */
const filterData = function () {
/* reset specify chart */
const chart = chartStore.chartManager.children[chartIndex]
chart.reset()
/* reset specify canvas */
canvasStore.canvas.reset()
canvasStore.canvas.format = lineOrScatter.value === false ? 'line' : 'scatter'
/* assign mode & library and create series*/
for (const meta of fileView.selectedFiles) {
/* append info to chart */
chart.addLibraryMode(meta.parameter._LIBRARY_, meta.parameter.MODE)
/* append series */
chart.seriesManager.addSeries({ id: meta.id, name: meta.name })
canvasStore.canvas.metaIds.push(meta.id)
}
/* set x-axis name */
chart.xAxisManager.setName(channelStore.xAxisSelected.name)
/* set y-axis name */
chart.yAxisManager.setName(channelStore.yAxisSelected.name)
/* set x-axis label */
chart.xAxisManager.setAxisLabel({
text: channelStore.xAxisSelected.defaultUnit,
scale: channelStore.xAxisSelected.unit[channelStore.xAxisSelected.defaultUnit],
option: channelStore.xAxisSelected.unit,
})
const xChannel = JSON.parse(JSON.stringify(channelStore.xAxisSelected))
canvasStore.canvas.x.channel = xChannel
canvasStore.canvas.x.selectUnit = xChannel.defaultUnit
canvasStore.canvas.x.unit = xChannel.unit
/* set y-axis label */
chart.yAxisManager.setAxisLabel({
text: channelStore.yAxisSelected.defaultUnit,
scale: channelStore.yAxisSelected.unit[channelStore.yAxisSelected.defaultUnit],
option: channelStore.yAxisSelected.unit,
})
const yChannel = JSON.parse(JSON.stringify(channelStore.yAxisSelected))
canvasStore.canvas.y.channel = yChannel
canvasStore.canvas.y.selectUnit = yChannel.defaultUnit
canvasStore.canvas.y.unit = yChannel.unit
emit('filter-data', {
pattern: {
id: simpleSelectModel.value.id,
name: simpleSelectModel.value.description,
parameter: { percentage: VTModeModel.value, window: slopModeModel.value },
},
data: {
id: fileView.selectedFiles.map((ele: any) => ele.id),
channel: [channelStore.xAxisSelected.id, channelStore.yAxisSelected.id],
},
})
}
defineExpose({
simpleSelectModel,
simpleOptions,
VTModeModel,
slopModeModel,
filterData,
})
</script>
<style lang=""></style>
+211 -211
View File
@@ -12,220 +12,220 @@ export default {
}, },
routes: [ routes: [
{ {
name: 'dashboard', name: 'data-analysis',
displayName: 'menu.dashboard', displayName: 'Analysis',
meta: { meta: {
icon: 'vuestic-iconset-dashboard', icon: 'vuestic-iconset-dashboard',
}, },
}, },
{ // {
name: 'statistics', // name: 'statistics',
displayName: 'menu.statistics', // displayName: 'menu.statistics',
meta: { // meta: {
icon: 'vuestic-iconset-statistics', // icon: 'vuestic-iconset-statistics',
}, // },
disabled: true, // disabled: true,
children: [ // children: [
{ // {
name: 'charts', // name: 'charts',
displayName: 'menu.charts', // displayName: 'menu.charts',
}, // },
{ // {
name: 'progress-bars', // name: 'progress-bars',
displayName: 'menu.progressBars', // displayName: 'menu.progressBars',
}, // },
], // ],
}, // },
{ // {
name: 'forms', // name: 'forms',
displayName: 'menu.forms', // displayName: 'menu.forms',
meta: { // meta: {
icon: 'vuestic-iconset-forms', // icon: 'vuestic-iconset-forms',
}, // },
disabled: true, // disabled: true,
children: [ // children: [
{ // {
name: 'form-elements', // name: 'form-elements',
displayName: 'menu.formElements', // displayName: 'menu.formElements',
}, // },
{ // {
name: 'medium-editor', // name: 'medium-editor',
displayName: 'menu.mediumEditor', // displayName: 'menu.mediumEditor',
}, // },
], // ],
}, // },
{ // {
name: 'tables', // name: 'tables',
displayName: 'menu.tables', // displayName: 'menu.tables',
meta: { // meta: {
icon: 'vuestic-iconset-tables', // icon: 'vuestic-iconset-tables',
}, // },
children: [ // children: [
{ // {
name: 'markup', // name: 'markup',
displayName: 'menu.markupTables', // displayName: 'menu.markupTables',
}, // },
// { // // {
// name: 'data', // // name: 'data',
// displayName: 'menu.dataTables', // // displayName: 'menu.dataTables',
// }, // // },
], // ],
}, // },
{ // {
name: 'ui', // name: 'ui',
displayName: 'menu.uiElements', // displayName: 'menu.uiElements',
meta: { // meta: {
icon: 'vuestic-iconset-ui-elements', // icon: 'vuestic-iconset-ui-elements',
}, // },
disabled: true, // disabled: true,
children: [ // children: [
{ // {
name: 'buttons', // name: 'buttons',
displayName: 'menu.buttons', // displayName: 'menu.buttons',
}, // },
{ // {
name: 'cards', // name: 'cards',
displayName: 'menu.cards', // displayName: 'menu.cards',
}, // },
{ // {
name: 'chat', // name: 'chat',
displayName: 'menu.chat', // displayName: 'menu.chat',
}, // },
{ // {
name: 'chips', // name: 'chips',
displayName: 'menu.chips', // displayName: 'menu.chips',
}, // },
{ // {
name: 'collapses', // name: 'collapses',
displayName: 'menu.collapses', // displayName: 'menu.collapses',
}, // },
{ // {
name: 'colors', // name: 'colors',
displayName: 'menu.colors', // displayName: 'menu.colors',
}, // },
// { // // {
// name: 'color-pickers', // // name: 'color-pickers',
// displayName: 'menu.colorPickers', // // displayName: 'menu.colorPickers',
// }, // // },
{ // {
name: 'file-upload', // name: 'file-upload',
displayName: 'menu.fileUpload', // displayName: 'menu.fileUpload',
}, // },
{ // {
name: 'grid', // name: 'grid',
displayName: 'menu.grid', // displayName: 'menu.grid',
}, // },
{ // {
name: 'icon-sets', // name: 'icon-sets',
displayName: 'menu.icons', // displayName: 'menu.icons',
children: [ // children: [
{ // {
displayName: 'concrete', // displayName: 'concrete',
name: 'icon-set', // name: 'icon-set',
}, // },
], // ],
}, // },
{ // {
name: 'lists', // name: 'lists',
displayName: 'menu.lists', // displayName: 'menu.lists',
}, // },
{ // {
name: 'modals', // name: 'modals',
displayName: 'menu.modals', // displayName: 'menu.modals',
}, // },
{ // {
name: 'notifications', // name: 'notifications',
displayName: 'menu.notifications', // displayName: 'menu.notifications',
}, // },
{ // {
name: 'popovers', // name: 'popovers',
displayName: 'menu.popovers', // displayName: 'menu.popovers',
}, // },
{ // {
name: 'rating', // name: 'rating',
displayName: 'menu.rating', // displayName: 'menu.rating',
}, // },
{ // {
name: 'sliders', // name: 'sliders',
displayName: 'menu.sliders', // displayName: 'menu.sliders',
}, // },
{ // {
name: 'spacing', // name: 'spacing',
displayName: 'menu.spacing', // displayName: 'menu.spacing',
}, // },
{ // {
name: 'spinners', // name: 'spinners',
displayName: 'menu.spinners', // displayName: 'menu.spinners',
}, // },
{ // {
name: 'tabs', // name: 'tabs',
displayName: 'menu.tabs', // displayName: 'menu.tabs',
}, // },
// { // // {
// name: "timelines", // // name: "timelines",
// displayName: "menu.timelines", // // displayName: "menu.timelines",
// }, // // },
{ // {
name: 'tree-view', // name: 'tree-view',
displayName: 'menu.treeView', // displayName: 'menu.treeView',
}, // },
{ // {
name: 'typography', // name: 'typography',
displayName: 'menu.typography', // displayName: 'menu.typography',
}, // },
], // ],
}, // },
{ // {
name: 'maps', // name: 'maps',
displayName: 'menu.maps', // displayName: 'menu.maps',
meta: { // meta: {
icon: 'vuestic-iconset-maps', // icon: 'vuestic-iconset-maps',
}, // },
disabled: true, // disabled: true,
children: [ // children: [
{ // {
name: 'maplibre-maps', // name: 'maplibre-maps',
displayName: 'menu.maplibre-maps', // displayName: 'menu.maplibre-maps',
}, // },
{ // {
name: 'yandex-maps', // name: 'yandex-maps',
displayName: 'menu.yandex-maps', // displayName: 'menu.yandex-maps',
}, // },
{ // {
name: 'leaflet-maps', // name: 'leaflet-maps',
displayName: 'menu.leaflet-maps', // displayName: 'menu.leaflet-maps',
}, // },
{ // {
name: 'bubble-maps', // name: 'bubble-maps',
displayName: 'menu.bubble-maps', // displayName: 'menu.bubble-maps',
}, // },
{ // {
name: 'line-maps', // name: 'line-maps',
displayName: 'menu.line-maps', // displayName: 'menu.line-maps',
}, // },
], // ],
}, // },
{ // {
name: 'pages', // name: 'pages',
displayName: 'menu.pages', // displayName: 'menu.pages',
meta: { // meta: {
icon: 'vuestic-iconset-files', // icon: 'vuestic-iconset-files',
}, // },
disabled: true, // disabled: true,
children: [ // children: [
{ // {
name: 'login', // name: 'login',
displayName: 'menu.login-singup', // displayName: 'menu.login-singup',
}, // },
{ // {
name: '404-pages', // name: '404-pages',
displayName: 'menu.404-pages', // displayName: 'menu.404-pages',
}, // },
{ // {
name: 'faq', // name: 'faq',
displayName: 'menu.faq', // displayName: 'menu.faq',
}, // },
], // ],
}, // },
] as INavigationRoute[], ] as INavigationRoute[],
} }
-46
View File
@@ -1,46 +0,0 @@
<template>
<component :is="chartComponent" ref="chart" class="va-chart" :chart-options="chartOptions" :chart-data="data" />
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { defaultConfig, chartTypesMap } from './vaChartConfigs'
import { TChartData } from '../../data/types'
const props = defineProps<{
data: TChartData
options?: TChartOptions<'line' | 'bar' | 'bubble' | 'doughnut' | 'pie'>
type: keyof typeof chartTypesMap
}>()
const chart = ref()
const chartComponent = computed(() => chartTypesMap[props.type])
const chartOptions = computed(() => ({
...defaultConfig,
...props.options,
}))
</script>
<style lang="scss">
.va-chart {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
> * {
height: 100%;
width: 100%;
}
canvas {
width: 100%;
height: auto;
min-height: 320px;
}
}
</style>
@@ -1,17 +0,0 @@
<template>
<Bar :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Bar } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale } from 'chart.js'
import { TBarChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale)
const props = defineProps<{
chartData: TBarChartData
chartOptions?: TChartOptions<'bar'>
}>()
</script>
@@ -1,17 +0,0 @@
<template>
<Bubble :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Bubble } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, PointElement, LinearScale } from 'chart.js'
import { TBubbleChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, PointElement, LinearScale)
const props = defineProps<{
chartData: TBubbleChartData
chartOptions?: TChartOptions<'bubble'>
}>()
</script>
@@ -1,17 +0,0 @@
<template>
<Doughnut :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Doughnut } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale } from 'chart.js'
import { TDoughnutChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
const props = defineProps<{
chartData: TDoughnutChartData
chartOptions?: TChartOptions<'doughnut'>
}>()
</script>
@@ -1,26 +0,0 @@
<template>
<Bar :chart-options="{ ...chartOptions, ...horizontalBarOptions }" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Bar } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale } from 'chart.js'
import { TBarChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, BarElement, LinearScale, CategoryScale)
const horizontalBarOptions = {
indexAxis: 'y' as 'x' | 'y',
elements: {
bar: {
borderWidth: 1,
},
},
}
const props = defineProps<{
chartData: TBarChartData
chartOptions?: TChartOptions<'bar'>
}>()
</script>
@@ -1,27 +0,0 @@
<template>
<Line :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Line } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
LineElement,
LinearScale,
PointElement,
CategoryScale,
Filler,
} from 'chart.js'
import { TLineChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale, Filler)
const props = defineProps<{
chartData: TLineChartData
chartOptions?: TChartOptions<'line'>
}>()
</script>
@@ -1,17 +0,0 @@
<template>
<Pie :chart-options="chartOptions" :chart-data="props.chartData" />
</template>
<script setup lang="ts">
import { Pie } from 'vue-chartjs'
import type { TChartOptions } from 'vue-chartjs/dist/types'
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale } from 'chart.js'
import { TPieChartData } from '../../../data/types'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
const props = defineProps<{
chartData: TPieChartData
chartOptions?: TChartOptions<'pie'>
}>()
</script>
@@ -1,48 +0,0 @@
import { defineAsyncComponent } from 'vue'
export const defaultConfig = {
plugins: {
legend: {
position: 'bottom',
labels: {
font: {
color: '#34495e',
family: 'sans-serif',
size: 14,
},
usePointStyle: true,
},
},
tooltip: {
bodyFont: {
size: 14,
family: 'sans-serif',
},
boxPadding: 4,
},
},
datasets: {
line: {
fill: 'origin',
tension: 0.3,
borderColor: 'transparent',
},
bubble: {
borderColor: 'transparent',
},
bar: {
borderColor: 'transparent',
},
},
maintainAspectRatio: false,
animation: true,
}
export const chartTypesMap = {
pie: defineAsyncComponent(() => import('./chart-types/PieChart.vue')),
doughnut: defineAsyncComponent(() => import('./chart-types/DoughnutChart.vue')),
bubble: defineAsyncComponent(() => import('./chart-types/BubbleChart.vue')),
line: defineAsyncComponent(() => import('./chart-types/LineChart.vue')),
bar: defineAsyncComponent(() => import('./chart-types/BarChart.vue')),
'horizontal-bar': defineAsyncComponent(() => import('./chart-types/HorizontalBarChart.vue')),
}
@@ -1,189 +0,0 @@
<template>
<div ref="editorElement" class="va-medium-editor content">
<slot />
</div>
</template>
<script setup lang="ts">
import { ref, Ref, onMounted, onBeforeUnmount } from 'vue'
import MediumEditor from 'medium-editor'
const props = withDefaults(
defineProps<{
editorOptions?: {
buttonLabels: string
autoLink: boolean
toolbar: {
buttons: string[]
}
}
}>(),
{
editorOptions: () => ({
buttonLabels: 'fontawesome',
autoLink: true,
toolbar: {
buttons: ['bold', 'italic', 'underline', 'anchor', 'h1', 'h2', 'h3'],
},
}),
},
)
const emit = defineEmits<{
(e: 'initialized', editor: typeof MediumEditor): void
}>()
const editorElement: Ref<null | HTMLElement> = ref(null)
let editor: typeof MediumEditor | null = null
onMounted(() => {
if (!editorElement.value) {
return
}
editor = new MediumEditor(editorElement.value, props.editorOptions)
emit('initialized', editor)
})
onBeforeUnmount(() => {
if (editor) {
editor.destroy()
}
})
</script>
<style lang="scss">
@import 'medium-editor/src/sass/medium-editor';
@import 'variables';
$medium-editor-shadow: var(--va-box-shadow);
$medium-editor-background-color: var(--va-divider);
$medium-editor-text-color: var(--va-dark);
$medium-editor-active-background-color: var(--va-primary);
$medium-editor-active-text-color: var(--va-white);
.va-medium-editor {
margin-bottom: var(--va-medium-editor-margin-bottom);
min-width: var(--va-medium-editor-min-width);
max-width: var(--va-medium-editor-max-width);
&:focus {
outline: none;
}
&.content {
i {
font-style: italic;
}
}
}
// isn't a part of the .va-medium-editor, so can't be places inside it
.medium-editor-toolbar,
.medium-editor-toolbar-form,
.medium-editor-toolbar-actions,
.medium-editor-toolbar-anchor-preview {
box-shadow: $medium-editor-shadow;
background-color: $medium-editor-background-color;
border-radius: 1.5rem;
height: 44px;
line-height: 42px;
}
.medium-editor-toolbar-anchor-preview {
a {
padding: 0 2rem;
margin: 0;
line-height: 44px;
}
}
.medium-editor-toolbar {
box-shadow: $medium-editor-shadow;
.medium-editor-toolbar-actions {
overflow: hidden;
height: 44px;
}
.medium-editor-action {
margin: 0;
border: 0;
padding: 0.375rem 1rem;
height: 44px;
background-color: $medium-editor-background-color;
box-shadow: none;
border-radius: 0;
i {
color: $medium-editor-text-color;
}
&.medium-editor-button-active {
background-color: $medium-editor-active-background-color;
color: $medium-editor-active-text-color;
i {
color: $medium-editor-active-text-color;
}
}
}
& > .medium-editor-action:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: 0;
}
& > .medium-editor-action + .medium-editor-action {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 0;
}
}
.medium-editor-toolbar-form {
color: $medium-editor-text-color;
overflow: hidden;
a {
color: $medium-editor-text-color;
transform: translateY(1px);
}
input {
margin-left: 4px !important;
transform: translateY(-2px);
border-radius: 13px;
}
.medium-editor-toolbar-close {
margin-right: 1rem;
}
}
.medium-toolbar-arrow-under::after {
border-color: $medium-editor-background-color transparent transparent transparent;
top: 100%;
}
.medium-toolbar-arrow-over::before {
border-color: transparent transparent var(--va-primary) transparent;
}
.medium-editor-toolbar-anchor-preview {
// @include va-button($btn-padding-y-nrm, $btn-padding-x-nrm, $btn-font-size-nrm, $btn-line-height-nrm, $btn-border-radius-nrm);
.medium-editor-toolbar-anchor-preview {
margin: 0;
}
}
.medium-editor-anchor-preview {
max-width: 50%;
a {
color: $medium-editor-text-color;
text-decoration: none;
}
}
</style>
@@ -1,9 +0,0 @@
:root {
--va-medium-editor-margin-bottom: 2.25rem;
--va-medium-editor-min-width: 6rem;
--va-medium-editor-max-width: 600px;
/* Toolbar */
--va-medium-editor-toolbar-max-width: 90%;
--va-medium-editor-toolbar-box-shadow: none;
}
+37
View File
@@ -0,0 +1,37 @@
import MQTT from '@/utils/mqtt'
import type { OnMessageCallback } from 'mqtt'
import { onUnmounted, ref } from 'vue'
export default function useMqtt() {
const PublicMqtt = ref<MQTT | null>(null)
const startMqtt = (val: string, callback: OnMessageCallback) => {
// set mqtt topic
PublicMqtt.value = new MQTT(val)
// init mqtt
PublicMqtt.value.init()
// link mqtt
PublicMqtt.value.link()
getMessage(callback)
}
const publish = (topic: string, message: string) => {
PublicMqtt.value?.publish(topic, message)
}
const getMessage = (callback: OnMessageCallback) => {
// PublicMqtt.value?.client.on('message', callback);
PublicMqtt.value?.get(callback)
}
onUnmounted(() => {
if (PublicMqtt.value) {
PublicMqtt.value.unsubscribes()
PublicMqtt.value.over()
}
})
return {
startMqtt,
publish,
}
}
-243
View File
@@ -1,243 +0,0 @@
export default [
'Afghanistan',
'Albania',
'Algeria',
'American Samoa',
'Andorra',
'Angola',
'Anguilla',
'Antarctica',
'Antigua and Barbuda',
'Argentina',
'Armenia',
'Aruba',
'Australia',
'Austria',
'Azerbaijan',
'Bahamas',
'Bahrain',
'Bangladesh',
'Barbados',
'Belarus',
'Belgium',
'Belize',
'Benin',
'Bermuda',
'Bhutan',
'Bolivia',
'Bosnia and Herzegowina',
'Botswana',
'Bouvet Island',
'Brazil',
'British Indian Ocean Territory',
'Brunei Darussalam',
'Bulgaria',
'Burkina Faso',
'Burundi',
'Cambodia',
'Cameroon',
'Canada',
'Cape Verde',
'Cayman Islands',
'Central African Republic',
'Chad',
'Chile',
'China',
'Christmas Island',
'Cocos (Keeling) Islands',
'Colombia',
'Comoros',
'Congo',
'Congo, the Democratic Republic of the',
'Cook Islands',
'Costa Rica',
"Cote d'Ivoire",
'Croatia (Hrvatska)',
'Cuba',
'Cyprus',
'Czech Republic',
'Denmark',
'Djibouti',
'Dominica',
'Dominican Republic',
'East Timor',
'Ecuador',
'Egypt',
'El Salvador',
'Equatorial Guinea',
'Eritrea',
'Estonia',
'Ethiopia',
'Falkland Islands (Malvinas)',
'Faroe Islands',
'Fiji',
'Finland',
'France',
'France Metropolitan',
'French Guiana',
'French Polynesia',
'French Southern Territories',
'Gabon',
'Gambia',
'Georgia',
'Germany',
'Ghana',
'Gibraltar',
'Greece',
'Greenland',
'Grenada',
'Guadeloupe',
'Guam',
'Guatemala',
'Guinea',
'Guinea-Bissau',
'Guyana',
'Haiti',
'Heard and Mc Donald Islands',
'Holy See (Vatican City State)',
'Honduras',
'Hong Kong',
'Hungary',
'Iceland',
'India',
'Indonesia',
'Iran (Islamic Republic of)',
'Iraq',
'Ireland',
'Israel',
'Italy',
'Jamaica',
'Japan',
'Jordan',
'Kazakhstan',
'Kenya',
'Kiribati',
"Korea, Democratic People's Republic of",
'Korea, Republic of',
'Kuwait',
'Kyrgyzstan',
"Lao, People's Democratic Republic",
'Latvia',
'Lebanon',
'Lesotho',
'Liberia',
'Libyan Arab Jamahiriya',
'Liechtenstein',
'Lithuania',
'Luxembourg',
'Macau',
'Macedonia, The Former Yugoslav Republic of',
'Madagascar',
'Malawi',
'Malaysia',
'Maldives',
'Mali',
'Malta',
'Marshall Islands',
'Martinique',
'Mauritania',
'Mauritius',
'Mayotte',
'Mexico',
'Micronesia, Federated States of',
'Moldova, Republic of',
'Monaco',
'Mongolia',
'Montserrat',
'Morocco',
'Mozambique',
'Myanmar',
'Namibia',
'Nauru',
'Nepal',
'Netherlands',
'Netherlands Antilles',
'New Caledonia',
'New Zealand',
'Nicaragua',
'Niger',
'Nigeria',
'Niue',
'Norfolk Island',
'Northern Mariana Islands',
'Norway',
'Oman',
'Pakistan',
'Palau',
'Panama',
'Papua New Guinea',
'Paraguay',
'Peru',
'Philippines',
'Pitcairn',
'Poland',
'Portugal',
'Puerto Rico',
'Qatar',
'Reunion',
'Romania',
'Russian Federation',
'Rwanda',
'Saint Kitts and Nevis',
'Saint Lucia',
'Saint Vincent and the Grenadines',
'Samoa',
'San Marino',
'Sao Tome and Principe',
'Saudi Arabia',
'Senegal',
'Serbia',
'Seychelles',
'Sierra Leone',
'Singapore',
'Slovakia (Slovak Republic)',
'Slovenia',
'Solomon Islands',
'Somalia',
'South Africa',
'South Georgia and the South Sandwich Islands',
'Spain',
'Sri Lanka',
'St. Helena',
'St. Pierre and Miquelon',
'Sudan',
'Suriname',
'Svalbard and Jan Mayen Islands',
'Swaziland',
'Sweden',
'Switzerland',
'Syrian Arab Republic',
'Taiwan, Province of China',
'Tajikistan',
'Tanzania, United Republic of',
'United States of America',
'Thailand',
'Togo',
'Tokelau',
'Tonga',
'Trinidad and Tobago',
'Tunisia',
'Turkey',
'Turkmenistan',
'Turks and Caicos Islands',
'Tuvalu',
'Uganda',
'Ukraine',
'United Arab Emirates',
'United Kingdom',
'United States',
'United States Minor Outlying Islands',
'Uruguay',
'Uzbekistan',
'Vanuatu',
'Venezuela',
'Vietnam',
'Virgin Islands (British)',
'Virgin Islands (U.S.)',
'Wallis and Futuna Islands',
'Western Sahara',
'Yemen',
'Yugoslavia',
'Zambia',
'Zimbabwe',
]
+13
View File
@@ -0,0 +1,13 @@
import axios, { Axios } from 'axios'
export const setBaseURL = function (baseURL: string) {
if (baseURL) {
axios.defaults.baseURL = `http://${baseURL}:3000`
}
}
setBaseURL(location.href.split('/')[2].split(':')[0])
export const getAxios = function (): Axios {
return axios
}
-30
View File
@@ -1,30 +0,0 @@
import { TBarChartData } from '../types'
export const barChartData: TBarChartData = {
labels: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
datasets: [
{
label: 'Last year',
backgroundColor: 'primary',
data: [50, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11],
},
{
label: 'Current year',
backgroundColor: 'info',
data: [50, 10, 22, 39, 15, 20, 85, 32, 60, 50, 20, 30],
},
],
}
-231
View File
@@ -1,231 +0,0 @@
import { TBubbleChartData } from '../types'
export const bubbleChartData: TBubbleChartData = {
datasets: [
{
label: 'USA',
backgroundColor: 'danger',
data: [
{
x: 23,
y: 25,
r: 15,
},
{
x: 40,
y: 10,
r: 10,
},
{
x: 30,
y: 22,
r: 30,
},
{
x: 7,
y: 43,
r: 40,
},
{
x: 23,
y: 27,
r: 12,
},
{
x: 20,
y: 15,
r: 11,
},
{
x: 7,
y: 10,
r: 35,
},
{
x: 10,
y: 20,
r: 40,
},
],
},
{
label: 'Russia',
backgroundColor: 'primary',
data: [
{
x: 0,
y: 30,
r: 15,
},
{
x: 20,
y: 20,
r: 20,
},
{
x: 15,
y: 15,
r: 50,
},
{
x: 31,
y: 46,
r: 30,
},
{
x: 20,
y: 14,
r: 25,
},
{
x: 34,
y: 17,
r: 30,
},
{
x: 44,
y: 44,
r: 10,
},
{
x: 39,
y: 25,
r: 35,
},
],
},
{
label: 'Canada',
backgroundColor: 'warning',
data: [
{
x: 10,
y: 30,
r: 45,
},
{
x: 10,
y: 50,
r: 20,
},
{
x: 5,
y: 5,
r: 30,
},
{
x: 40,
y: 30,
r: 20,
},
{
x: 33,
y: 15,
r: 18,
},
{
x: 40,
y: 20,
r: 40,
},
{
x: 33,
y: 33,
r: 40,
},
],
},
{
label: 'Belarus',
backgroundColor: 'info',
data: [
{
x: 35,
y: 30,
r: 45,
},
{
x: 25,
y: 40,
r: 35,
},
{
x: 5,
y: 5,
r: 30,
},
{
x: 5,
y: 20,
r: 40,
},
{
x: 10,
y: 40,
r: 15,
},
{
x: 3,
y: 10,
r: 10,
},
{
x: 15,
y: 40,
r: 40,
},
{
x: 7,
y: 15,
r: 10,
},
],
},
{
label: 'Ukraine',
backgroundColor: 'success',
data: [
{
x: 25,
y: 10,
r: 40,
},
{
x: 17,
y: 40,
r: 40,
},
{
x: 35,
y: 10,
r: 20,
},
{
x: 3,
y: 40,
r: 10,
},
{
x: 40,
y: 40,
r: 40,
},
{
x: 20,
y: 10,
r: 10,
},
{
x: 10,
y: 27,
r: 35,
},
{
x: 7,
y: 26,
r: 40,
},
],
},
],
}
@@ -1,35 +0,0 @@
import { computed, ref } from '@vue/reactivity'
import { watch } from 'vue'
import { useColors, useGlobalConfig } from 'vuestic-ui'
type chartColors = string | string[]
export function useChartColors(chartColors = [] as chartColors, alfa = 0.6) {
const { getGlobalConfig } = useGlobalConfig()
const { setHSLAColor, getColor } = useColors()
const generateHSLAColors = (colors: chartColors) =>
typeof colors === 'string'
? setHSLAColor(getColor(colors), { a: alfa })
: colors.map((color) => setHSLAColor(getColor(color), { a: alfa }))
const generateColors = (colors: chartColors) =>
typeof colors === 'string' ? getColor(colors) : colors.map((color) => getColor(color))
const generatedHSLAColors = ref(generateHSLAColors(chartColors))
const generatedColors = ref(generateColors(chartColors))
const theme = computed(() => getGlobalConfig().colors!)
watch(theme, () => {
generatedHSLAColors.value = generateHSLAColors(chartColors)
generatedColors.value = generateColors(chartColors)
})
return {
generateHSLAColors,
generateColors,
generatedColors,
generatedHSLAColors,
}
}
@@ -1,20 +0,0 @@
import { computed, ComputedRef } from '@vue/reactivity'
import { useChartColors } from './useChartColors'
import { TChartData } from '../../types'
export function useChartData<T extends TChartData>(data: T, alfa?: number): ComputedRef<T> {
const datasetsColors = data.datasets.map((dataset) => dataset.backgroundColor as string)
const datasetsThemesColors = datasetsColors.map(
(colors) => useChartColors(colors, alfa)[alfa ? 'generatedHSLAColors' : 'generatedColors'],
)
return computed(() => {
const datasets = data.datasets.map((dataset, idx) => ({
...dataset,
backgroundColor: datasetsThemesColors[idx].value,
}))
return { ...data, datasets } as T
})
}
-12
View File
@@ -1,12 +0,0 @@
import { TDoughnutChartData } from '../types'
export const doughnutChartData: TDoughnutChartData = {
labels: ['North America', 'South America', 'Australia'],
datasets: [
{
label: 'Population (millions)',
backgroundColor: ['danger', 'info', 'primary'],
data: [2478, 5267, 734],
},
],
}
-30
View File
@@ -1,30 +0,0 @@
import { TBarChartData } from '../types'
export const horizontalBarChartData: TBarChartData = {
labels: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
datasets: [
{
label: 'Vuestic Satisfaction Score',
backgroundColor: 'primary',
data: [80, 90, 50, 70, 60, 90, 50, 90, 80, 40, 72, 93],
},
{
label: 'Bulma Satisfaction Score',
backgroundColor: 'danger',
data: [20, 30, 20, 40, 50, 40, 15, 60, 30, 20, 42, 53],
},
],
}
-6
View File
@@ -1,6 +0,0 @@
export { bubbleChartData } from './bubbleChartData'
export { doughnutChartData } from './doughnutChartData'
export { barChartData } from './barChartData'
export { horizontalBarChartData } from './horizontalBarChartData'
export { lineChartData } from './lineChartData'
export { pieChartData } from './pieChartData'
-44
View File
@@ -1,44 +0,0 @@
import { TLineChartData } from '../types'
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
const getSize = (minSize = 5) => Math.max(minSize, new Date().getMonth())
const size = getSize()
const generateValue = () => Math.floor(Math.random() * 100)
const generateArray = (length: number) => Array.from(Array(length), generateValue)
const generateYLabels = () => {
const flip = !!Math.floor(Math.random() * 2)
return flip ? ['Debit', 'Credit'] : ['Credit', 'Debit']
}
const yLabels = generateYLabels()
export const lineChartData: TLineChartData = {
labels: months.slice(0, size),
datasets: [
{
label: yLabels[0],
backgroundColor: 'primary',
data: generateArray(size),
},
{
label: yLabels[1],
backgroundColor: 'secondary',
data: generateArray(size),
},
],
}
-12
View File
@@ -1,12 +0,0 @@
import { TLineChartData } from '../types'
export const pieChartData: TLineChartData = {
labels: ['Africa', 'Asia', 'Europe'],
datasets: [
{
label: 'Population (millions)',
backgroundColor: ['primary', 'warning', 'danger'],
data: [2478, 5267, 734],
},
],
}
+20
View File
@@ -0,0 +1,20 @@
export default {
name: 'Idle',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {},
charts: {},
}
+94
View File
@@ -0,0 +1,94 @@
export default {
name: 'Cali Mode - test',
parameter: ['ADC_DAC_CHANNEL_15', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'DAC_LEVEL_V_OUT_15', 'DAC_VOLT_BUTTON'], // 這個mode用到的參數
showParameter: ['ADC_DAC_CHANNEL_15', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'DAC_LEVEL_V_OUT_15', 'DAC_VOLT_BUTTON'], // 有要秀給user看的參數
headerParameter: () => [
'ADC_DAC_CHANNEL_15',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'DAC_LEVEL_V_OUT_15',
'DAC_VOLT_BUTTON',
], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'us',
},
0: {
name: 'I_in',
unit: {
nA: 1,
},
defaultUnit: 'nA',
},
1: {
name: 'V_in/V_out',
unit: {
uV: 1,
},
defaultUnit: 'uV',
},
2: {
name: 'Gain',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Cali Mode - test',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'ADC',
x1: {
channel: 'time',
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
+87
View File
@@ -0,0 +1,87 @@
export default {
name: 'Cali DAC - test',
parameter: ['CTRL_HIGH_Z_15', 'DAC_VOLT'], // 這個mode用到的參數
showParameter: ['CTRL_HIGH_Z_15', 'DAC_VOLT'], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'us',
},
0: {
name: 'I_in',
unit: {
nA: 1,
},
defaultUnit: 'nA',
},
1: {
name: 'V_in/V_out',
unit: {
uV: 1,
},
defaultUnit: 'uV',
},
2: {
name: 'Gain',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Cali DAC - test',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'DAC',
x1: {
channel: 'time',
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,97 @@
export default {
name: 'Chronoamperometry',
parameter: ['CA_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'CA_VOLT', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['CA_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Chronoamperometric',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'chrono',
x1: {
channel: 'time',
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,167 @@
export default {
name: 'Chronopotentiometry',
parameter: [
'Charge',
'Const_Current_value',
'SAMPLE_RATE',
'VOLTSTOP_MAX',
'VOLTSTOP_MIN',
'CC_CP_SPEED',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'TIME_DURATION',
], // 這個mode用到的參數
showParameter: [
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
'SAMPLE_RATE',
'Charge',
'Const_Current_value',
'VOLTSTOP_MAX',
'VOLTSTOP_MIN',
'TIME_DURATION',
], // 有要秀給user看的參數
headerParameter: () => [
'Charge',
'Const_Current_value',
'SAMPLE_RATE',
'VOLTSTOP_MAX',
'VOLTSTOP_MIN',
'CC_CP_SPEED',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'TIME_DURATION',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
name: 'sum_cnt',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
4: {
name: 'sum_adc_delta_Iin',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
5: {
name: 'sum_adc_delta_Voutin',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
6: {
name: 'resis',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
},
charts: {
default: [
{
name: 'Chronopotentiometry',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'CP',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,127 @@
export default {
name: 'Constant Current',
parameter: [
'Charge',
'Const_Current_value',
'SAMPLE_RATE',
'VOLTSTOP_MAX',
'VOLTSTOP_MIN',
'CC_CP_SPEED',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'TIME_DURATION',
], // 這個mode用到的參數
showParameter: [
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
'SAMPLE_RATE',
'Charge',
'Const_Current_value',
'VOLTSTOP_MAX',
'VOLTSTOP_MIN',
'TIME_DURATION',
], // 有要秀給user看的參數
headerParameter: () => [
'Charge',
'Const_Current_value',
'SAMPLE_RATE',
'VOLTSTOP_MAX',
'VOLTSTOP_MIN',
'CC_CP_SPEED',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'TIME_DURATION',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Constant Current',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'CC',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+134
View File
@@ -0,0 +1,134 @@
export default {
name: 'Cycle I-V',
parameter: [
'VOLT_ORIGIN',
'VOLT_FINAL',
'VOLT_STEP',
'STEP_TIME',
'SAMPLE_RATE',
'CYCLE_NUMBER',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
], // 這個mode用到的參數
showParameter: [
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
'VOLT_ORIGIN',
'VOLT_FINAL',
'VOLT_STEP',
'STEP_TIME',
'SAMPLE_RATE',
'CYCLE_NUMBER',
], // 有要秀給user看的參數
headerParameter: () => [
'VOLT_ORIGIN',
'VOLT_FINAL',
'VOLT_STEP',
'STEP_TIME',
'SAMPLE_RATE',
'CYCLE_NUMBER',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
name: 'Cycle number',
unit: {
cycle: 1,
},
defaultUnit: 'cycle',
downloadUnit: null,
},
},
charts: {
default: [
{
name: 'Cycle I-V',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'CycleIV',
x1: {
channel: 1,
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,134 @@
export default {
name: 'Cyclic Voltammetry',
parameter: [
'VOLT_INITIAL',
'VOLT_MAX',
'VOLT_MIN',
'Scan_Rate',
'SAMPLE_RATE',
'CYCLE_NUMBER',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
], // 這個mode用到的參數
showParameter: [
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
'VOLT_INITIAL',
'VOLT_MAX',
'VOLT_MIN',
'Scan_Rate',
'SAMPLE_RATE',
'CYCLE_NUMBER',
], // 有要秀給user看的參數
headerParameter: () => [
'VOLT_INITIAL',
'VOLT_MAX',
'VOLT_MIN',
'Scan_Rate',
'SAMPLE_RATE',
'CYCLE_NUMBER',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
name: 'Cycle number',
unit: {
cycle: 1,
},
defaultUnit: 'cycle',
downloadUnit: null,
},
},
charts: {
default: [
{
name: 'Cyclic Voltammetry',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'CV',
x1: {
channel: 1,
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
+135
View File
@@ -0,0 +1,135 @@
export default {
name: 'Differential Pulse Voltammetry',
parameter: ['DPV_e_init', 'DPV_e_final', 'DPV_increment', 'DPV_amp', 'DPV_pul_width', 'DPV_step_time'], // 這個mode用到的參數
parameterInMode: {
0: ['DPV_e_init', 'DPV_e_final', 'DPV_increment', 'DPV_amp', 'DPV_pul_width', 'DPV_step_time'],
1: [
'DPV_e_init',
'DPV_e_1',
'DPV_e_2',
'DPV_e_final',
'DPV_increment',
'DPV_amp',
'DPV_pul_width',
'DPV_step_time',
'CYCLE_NUMBER',
'DPV_pulse_option',
'DPV_curr_rec',
],
2: [
'DPV_e_init',
'DPV_e_final',
'DPV_increment',
'DPV_amp',
'DPV_pul_width',
'DPV_step_time',
'CYCLE_NUMBER',
'DPV_notify_rate',
'DPV_engineering_enable',
'DPV_e_1',
'DPV_e_2',
'DPV_pulse_option',
],
}, // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
name: 'Cycle number',
unit: {
cycle: 1,
},
defaultUnit: 'cycle',
downloadUnit: null,
},
},
charts: {
default: [
{
name: 'Open Circuit Potential',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'OCP',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+93
View File
@@ -0,0 +1,93 @@
export default {
name: 'Dev Mode',
parameter: ['ADC_VALUE_I'],
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
},
0: {
name: '0',
unit: {
default: 1,
},
defaultUnit: 'default',
},
1: {
name: '1',
unit: {
default: 1,
},
defaultUnit: 'default',
},
2: {
name: '2',
unit: {
default: 1,
},
defaultUnit: 'default',
},
3: {
name: '3',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Dev Mode',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'dev',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,97 @@
export default {
name: 'Function Generator',
parameter: ['DAC_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'DAC_VOLT', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['DAC_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Function Generator',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'FuncGen',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+97
View File
@@ -0,0 +1,97 @@
export default {
name: 'I-T Graph',
parameter: ['DAC_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'DAC_VOLT', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['DAC_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'I-T Graph',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'IT',
x1: {
channel: 'time',
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
+123
View File
@@ -0,0 +1,123 @@
export default {
name: 'I-V Curve',
parameter: [
'VOLT_ORIGIN',
'VOLT_FINAL',
'VOLT_STEP',
'STEP_TIME',
'SAMPLE_RATE',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
], // 這個mode用到的參數
showParameter: [
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
'VOLT_ORIGIN',
'VOLT_FINAL',
'VOLT_STEP',
'STEP_TIME',
'SAMPLE_RATE',
], // 有要秀給user看的參數
headerParameter: () => [
'VOLT_ORIGIN',
'VOLT_FINAL',
'VOLT_STEP',
'STEP_TIME',
'SAMPLE_RATE',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'I-V Curve',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'IV',
x1: {
channel: 1,
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,120 @@
export default {
name: 'Linear Sweep Voltammetry',
parameter: [
'VOLT_INITIAL',
'VOLT_EFINAL',
'Scan_Rate',
'SAMPLE_RATE',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
], // 這個mode用到的參數
showParameter: [
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
'CTRL_HIGH_Z_15',
'VOLT_INITIAL',
'VOLT_EFINAL',
'Scan_Rate',
'SAMPLE_RATE',
], // 有要秀給user看的參數
headerParameter: () => [
'VOLT_INITIAL',
'VOLT_EFINAL',
'Scan_Rate',
'SAMPLE_RATE',
'ADC_LEVEL_I_15',
'ADC_LEVEL_V_IN_15',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Linear Sweep Voltammetry',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'LSV',
x1: {
channel: 1,
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
+97
View File
@@ -0,0 +1,97 @@
export default {
name: 'Open Circuit Potential',
parameter: ['SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Open Circuit Potential',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'OCP',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,103 @@
export default {
name: 'Pulse Sensing',
parameter: ['V_initial', 't_pulse', 'CURR_REC'],
// parameter: ['V_initial', 't_pulse', 'CURR_REC_START', 'CURR_REC_END', 'segment_ui_order', 'segment_order', 'DATA_OUTPUT', 'CYCLE_NUMBER'], // 這個mode用到的參數
showParameter: ['V_initial', 't_pulse', 'CURR_REC'], // 有要秀給user看的參數
headerParameter: (parameterSet) => {
// [
// 'V_initial_0', 't_pulse_0', 'CURR_REC_START_0', 'CURR_REC_END_0',
// 'V_initial_1', 't_pulse_1', 'CURR_REC_START_1', 'CURR_REC_END_1',
// 'V_initial_2', 't_pulse_2', 'CURR_REC_START_2', 'CURR_REC_END_2',
// 'V_initial_3', 't_pulse_3', 'CURR_REC_START_3', 'CURR_REC_END_3',
// ]
const defaultParameter = ['V_initial', 't_pulse', 'CURR_REC']
const ret = []
for (let index = 0; index < 4; index++) {
if (parameterSet.segment_order[index] !== -1) {
ret.push(...defaultParameter.map((ele) => [ele, index]))
}
}
return ret
}, // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in_pul1',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'I_in_pul2',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
},
charts: {
default: [
{
name: 'Pulse Sensing',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'PulseSensing',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+102
View File
@@ -0,0 +1,102 @@
export default {
name: 'R-T Graph',
parameter: ['DAC_VOLT', 'SAMPLE_RATE', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['CTRL_HIGH_Z_15', 'DAC_VOLT', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['DAC_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'Resistor',
unit: {
: 1,
mohm: 1,
Ω: 1e3,
ohm: 1e3,
: 1e6,
kohm: 1e6,
: 1e9,
Mohm: 1e9,
},
defaultUnit: 'Ω',
downloadUnit: 'ohm',
},
},
charts: {
default: [
{
name: 'R-T Graph',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'RT',
x1: {
channel: 'time',
},
y1: {
channel: 2,
},
},
],
},
],
},
],
},
}
+87
View File
@@ -0,0 +1,87 @@
export default {
name: 'V-T Graph',
parameter: ['SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'V-T Graph',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'VT',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,97 @@
export default {
name: 'Chronoamperometry',
parameter: ['CA_VOLT', 'SAMPLE_RATE', 'GENERAL_LP_RTIA', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['GENERAL_LP_RTIA', 'CTRL_HIGH_Z_15', 'CA_VOLT', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['CA_VOLT', 'SAMPLE_RATE', 'GENERAL_LP_RTIA', 'TIME_DURATION'], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'Potential',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Chronoamperometric',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'chrono',
x1: {
channel: 'time',
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,273 @@
export default {
name: 'Constant Frequency',
parameter: [
'CF_DC_BIAS',
'CF_AC_AMP',
'CF_FREQ',
'CF_PPD',
'CF_SCALE',
'CF_DELAY',
'CF_AVERAGE_NUM',
'GENERAL_HS_RTIA',
], // 這個mode用到的參數
showParameter: [
'CF_DC_BIAS',
'CF_AC_AMP',
'CF_FREQ',
'CF_PPD',
'CF_SCALE',
'CF_DELAY',
'CF_AVERAGE_NUM',
'GENERAL_HS_RTIA',
], // 有要秀給user看的參數
headerParameter: () => [
'CF_DC_BIAS',
'CF_AC_AMP',
'CF_FREQ',
'CF_PPD',
'CF_SCALE',
'CF_DELAY',
'CF_AVERAGE_NUM',
'GENERAL_HS_RTIA',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
downloadUnit: 'ms',
},
0: {
name: 'Z_Imag_Raw',
unit: {
ohm: 1,
},
downloadUnit: 'ohm',
defaultUnit: 'ohm',
},
1: {
name: 'Z_Real_Raw',
unit: {
default: 1,
},
downloadUnit: 'ohm',
defaultUnit: 'ohm',
},
2: {
name: 'Frequency',
unit: {
mHz: 1,
Hz: 1e3,
kHz: 1e6,
},
downloadUnit: 'mHz',
defaultUnit: 'mHz',
},
// 3: {
// name: 'Cycle',
// unit: {
// cycle: 1,
// },
// defaultUnit: 'cycle',
// downloadUnit: null,
// },
4: {
name: 'Z_Imag',
unit: {
mohm: 1e-3,
: 1e-3,
ohm: 1,
Ω: 1,
kohm: 1e3,
: 1e3,
Mohm: 1e6,
: 1e6,
},
downloadUnit: 'ohm',
defaultUnit: 'Ω',
},
5: {
name: 'Z_Real',
unit: {
mohm: 1e-3,
: 1e-3,
ohm: 1,
Ω: 1,
kohm: 1e3,
: 1e3,
Mohm: 1e6,
: 1e6,
},
downloadUnit: 'ohm',
defaultUnit: 'Ω',
},
6: {
name: 'Impedance',
unit: {
mohm: 1e-3,
: 1e-3,
ohm: 1,
Ω: 1,
kohm: 1e3,
: 1e3,
Mohm: 1e6,
: 1e6,
},
downloadUnit: 'ohm',
defaultUnit: 'Ω',
},
7: {
name: 'Phase',
unit: {
millidegree: 1,
'°': 1e3,
},
downloadUnit: 'millidegree',
defaultUnit: '°',
},
8: {
name: 'Current',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
downloadUnit: 'nA',
defaultUnit: 'nA',
},
9: {
name: 'Level gain',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
10: {
name: 'notify_one',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
11: {
name: 'notify_two',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
12: {
name: 'notify_three',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
13: {
name: 'debug_amp[mV]',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Nyquist',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'Nyquist',
x1: {
channel: 5,
},
y1: {
channel: 4,
},
},
],
},
],
},
{
name: 'Bode',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'log',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y2: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'Bode',
x1: {
channel: 2,
},
y1: {
channel: 6,
},
y2: {
channel: 7,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,123 @@
export default {
name: 'Cyclic Voltammetry',
parameter: ['CV_E_INITIAL', 'CV_E1', 'CV_E2', 'CV_SCAN_RATE', 'SAMPLE_RATE', 'CYCLE_NUMBER', 'GENERAL_LP_RTIA'], // 這個mode用到的參數
showParameter: [
'GENERAL_LP_RTIA',
'CTRL_HIGH_Z_15',
'CV_E_INITIAL',
'CV_E1',
'CV_E2',
'CV_SCAN_RATE',
'SAMPLE_RATE',
'CYCLE_NUMBER',
], // 有要秀給user看的參數
headerParameter: () => [
'CV_E_INITIAL',
'CV_E1',
'CV_E2',
'CV_SCAN_RATE',
'SAMPLE_RATE',
'CYCLE_NUMBER',
'GENERAL_LP_RTIA',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'uA',
downloadUnit: 'mA',
},
1: {
name: 'V_out-V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
name: 'Cycle',
unit: {
cycle: 1,
},
defaultUnit: 'cycle',
downloadUnit: null,
},
},
charts: {
default: [
{
name: 'Cyclic Voltammetry',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'CV',
x1: {
channel: 1,
},
y1: {
channel: 0,
},
},
],
},
],
},
],
},
}
+93
View File
@@ -0,0 +1,93 @@
export default {
name: 'Dev Mode',
parameter: ['ADC_VALUE_I'],
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'us',
},
0: {
name: '0',
unit: {
default: 1,
},
defaultUnit: 'default',
},
1: {
name: '1',
unit: {
default: 1,
},
defaultUnit: 'default',
},
2: {
name: '2',
unit: {
default: 1,
},
defaultUnit: 'default',
},
3: {
name: '3',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Dev Mode',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'dev',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,275 @@
export default {
name: 'EIS',
parameter: [
'EIS_DC_BIAS',
'EIS_AC_AMP',
'EIS_FREQ',
'EIS_PPD',
'EIS_SCALE',
'EIS_DELAY',
'EIS_AVERAGE_NUM',
'GENERAL_HS_RTIA',
], // 這個mode用到的參數
showParameter: [
'EIS_DC_BIAS',
'EIS_AC_AMP',
'EIS_FREQ',
'EIS_PPD',
'EIS_SCALE',
'EIS_DELAY',
'EIS_AVERAGE_NUM',
'GENERAL_HS_RTIA',
], // 有要秀給user看的參數
headerParameter: () => [
'EIS_DC_BIAS',
'EIS_AC_AMP',
'EIS_FREQ',
'EIS_PPD',
'EIS_SCALE',
'EIS_DELAY',
'EIS_AVERAGE_NUM',
'GENERAL_HS_RTIA',
], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
downloadUnit: 'ms',
},
0: {
name: 'Z_Imag_Raw',
unit: {
ohm: 1,
},
downloadUnit: 'ohm',
defaultUnit: 'ohm',
},
1: {
name: 'Z_Real_Raw',
unit: {
default: 1,
},
downloadUnit: 'ohm',
defaultUnit: 'ohm',
},
2: {
name: 'Frequency',
unit: {
mHz: 1,
Hz: 1e3,
kHz: 1e6,
},
downloadUnit: 'mHz',
defaultUnit: 'mHz',
},
// 3: {
// name: 'Cycle',
// unit: {
// cycle: 1,
// },
// defaultUnit: 'cycle',
// downloadUnit: null,
// },
4: {
name: 'Z_Imag',
unit: {
mohm: 1e-3,
: 1e-3,
ohm: 1,
Ω: 1,
kohm: 1e3,
: 1e3,
Mohm: 1e6,
: 1e6,
},
downloadUnit: 'ohm',
defaultUnit: 'Ω',
},
5: {
name: 'Z_Real',
unit: {
mohm: 1e-3,
: 1e-3,
ohm: 1,
Ω: 1,
kohm: 1e3,
: 1e3,
Mohm: 1e6,
: 1e6,
},
downloadUnit: 'ohm',
defaultUnit: 'Ω',
},
6: {
name: 'Impedance',
unit: {
mohm: 1e-3,
: 1e-3,
ohm: 1,
Ω: 1,
kohm: 1e3,
: 1e3,
Mohm: 1e6,
: 1e6,
},
downloadUnit: 'ohm',
defaultUnit: 'Ω',
},
7: {
name: 'Phase',
unit: {
millidegree: 1,
'°': 1e3,
},
downloadUnit: 'millidegree',
defaultUnit: '°',
},
8: {
name: 'Current',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
downloadUnit: 'nA',
defaultUnit: 'nA',
},
9: {
name: 'Level gain',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
10: {
name: 'notify_one',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
11: {
name: 'notify_two',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
12: {
name: 'notify_three',
unit: {
default: 1,
},
downloadUnit: null,
defaultUnit: 'default',
},
13: {
name: 'debug_amp[mV]',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'Nyquist',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'Nyquist',
x1: {
channel: 5,
},
y1: {
channel: 4,
},
},
],
},
],
},
{
name: 'Bode',
description: '',
subplot: [
{
x1: {
type: 'value',
valScale: 'log',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y2: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'Bode',
x1: {
channel: 2,
},
y1: {
channel: 6,
},
y2: {
channel: 7,
},
},
],
},
],
},
],
},
}
+102
View File
@@ -0,0 +1,102 @@
export default {
name: 'R-T Graph',
parameter: ['RT_VOLT_SET', 'SAMPLE_RATE', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['RT_VOLT_SET', 'SAMPLE_RATE', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['RT_VOLT_SET', 'SAMPLE_RATE', 'GENERAL_LP_RTIA', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_out',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
2: {
name: 'Resistor',
unit: {
: 1,
mohm: 1,
Ω: 1e3,
ohm: 1e3,
: 1e6,
kohm: 1e6,
: 1e9,
Mohm: 1e9,
},
defaultUnit: 'Ω',
downloadUnit: 'ohm',
},
},
charts: {
default: [
{
name: 'R-T Graph',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'RT',
x1: {
channel: 'time',
},
y1: {
channel: 2,
},
},
],
},
],
},
],
},
}
+87
View File
@@ -0,0 +1,87 @@
export default {
name: 'V-T Graph',
parameter: ['SAMPLE_RATE', 'VT_MEASURE_VIN_RANGE', 'GENERAL_LP_RTIA', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['SAMPLE_RATE', 'VT_MEASURE_VIN_RANGE', 'GENERAL_LP_RTIA', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['SAMPLE_RATE', 'VT_MEASURE_VIN_RANGE', 'GENERAL_LP_RTIA', 'TIME_DURATION'], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
minute: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 'ms',
downloadUnit: 'ms',
},
0: {
name: 'I_in',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
1: {
name: 'V_in',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
charts: {
default: [
{
name: 'V-T Graph',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'VT',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
+579
View File
@@ -0,0 +1,579 @@
import PotentiostaticEIS from './PotentiostaticEIS'
import CyclicVoltammetry from './CyclicVoltammetry'
import DevMode from './DevMode'
import Chronoamperometry from './Chronoamperometry'
import VT from './VT'
import RT from './RT'
import ConstantFrequency from './ConstantFrequency'
import Idle from '../Common/Idle'
const EliteEIS = {
TIME_DURATION: {
type: 'number',
showName: 'Time duration',
componentType: 'input-range',
range: Object.freeze({ min: 0, max: 86400 }), // UI上能輸入的最大最小值
defaultValue: 0,
defaultUnit: 's',
downloadUnit: 's',
unit: {
ms: 1e-3,
s: 1,
m: 60,
h: 3600,
},
outputRawData: (val) => {
return parseInt(parseFloat(val))
},
outputReadabilityData: (val) => {
return parseInt(parseFloat(val))
},
},
CTRL_HIGH_Z_15: {
type: 'array',
showName: 'HighZ',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: 'On' },
{ value: 1, label: 'Off' },
],
range: ['On', 'Off'],
defaultValue: 1,
outputRawData: (val) => {
const highzArr = ['On', 'Off']
return highzArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const highzArr = ['On', 'Off']
return highzArr[parseInt(idx)]
},
},
CYCLE_NUMBER: {
type: 'number',
showName: 'Cycle',
componentType: 'input-range',
range: Object.freeze({ min: 1, max: 50000 }),
outputRawData: (val) => {
return parseInt(val)
},
outputReadabilityData: (val) => {
return parseInt(val)
},
defaultValue: 1,
defaultUnit: 'cycle',
downloadUnit: null,
unit: {
cycle: 1,
},
},
SAMPLE_RATE: {
type: 'number',
showName: 'Sample rate',
componentType: 'input-range',
range: Object.freeze({ min: 1, max: 1000 }),
outputRawData: (val, scale = 1) => {
return parseInt(parseFloat(val) * 10)
},
outputReadabilityData: (val, scale = 1) => {
return parseFloat(val) / 10
},
defaultValue: 1000,
defaultUnit: 'sps',
downloadUnit: 'sps',
unit: {
sps: 1,
},
},
GENERAL_HS_RTIA: {
type: 'array',
showName: 'Current range',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: '1' },
{ value: 1, label: '2' },
{ value: 2, label: '3' },
{ value: 3, label: '4' },
{ value: 4, label: 'Auto' },
],
range: ['1', '2', '3', '4', 'Auto'],
defaultValue: 4,
outputRawData: (val) => {
const numArr = ['1', '2', '3', '4', 'Auto']
return numArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const numArr = ['1', '2', '3', '4', 'Auto']
return numArr[parseInt(idx)]
},
},
GENERAL_LP_RTIA: {
type: 'array',
showName: 'Current Range',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: '<1.5 uA' },
{ value: 1, label: '1-60 uA' },
{ value: 2, label: '40-175 uA' },
{ value: 3, label: '>120 uA' },
{ value: 4, label: 'Auto' },
],
range: ['<1.5 uA', '1-60 uA', '40-175 uA', '>120 uA', 'Auto'],
defaultValue: 4,
outputRawData: (val) => {
const currentRangeArr = ['<1.5 uA', '1-60 uA', '40-175 uA', '>120 uA', 'Auto']
return currentRangeArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const currentRangeArr = ['<1.5 uA', '1-60 uA', '40-175 uA', '>120 uA', 'Auto']
return currentRangeArr[parseInt(idx)]
},
},
EIS_DC_BIAS: {
type: 'number',
showName: 'DC Volt',
componentType: 'input-field',
range: Object.freeze({ min: 2500, max: 50000 }), // UI上能輸入的最大最小值
outputRawData: (val, scale = 1) => {
return Math.round(parseInt(val) * 12.5 * scale + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return Math.round(parseInt(val - 25000) / 12.5) / scale
},
defaultValue: 25000,
defaultUnit: 'mV',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
},
EIS_AC_AMP: {
type: 'number',
showName: 'AC Amp',
componentType: 'input-field',
range: Object.freeze({ min: 0, max: 2047 }),
outputRawData: (val, scale = 1) => {
return Math.round((parseInt(val * scale) / 800) * 2047)
},
outputReadabilityData: (val, scale = 1) => {
return Math.round((parseInt(val) / 2047) * 800) / scale
},
defaultValue: 25,
defaultUnit: 'mV',
downloadUnit: 'mV',
unit: {
mV: 1,
},
},
EIS_FREQ: {
type: 'array',
showName: 'Frequency',
componentType: 'multi-input-field',
range: Object.freeze({ min: 1, max: 13333333 }),
outputRawData: (val) => {
return parseFloat(val) < 0.1 ? Math.round(0.1 / 0.015) : Math.round(parseFloat(val) / 0.015)
},
outputReadabilityData: (val) => {
return (parseFloat(val) * 0.015).toFixed(1)
},
defaultValue: [13333333, 7],
defaultUnit: 'Hz',
downloadUnit: 'Hz',
unit: {
Hz: 1,
},
},
EIS_PPD: {
type: 'number',
showName: 'Points per decades',
componentType: 'input-field',
range: Object.freeze({ min: 1, max: 10 }),
outputRawData: (val) => {
return parseInt(val)
},
outputReadabilityData: (val) => {
return parseInt(val)
},
defaultValue: 10,
defaultUnit: 'points',
downloadUnit: null,
unit: {
points: 1,
},
},
EIS_SCALE: {
type: 'array',
showName: 'Point spacing',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: 'Logarithm' },
{ value: 1, label: 'Linear' },
],
range: ['Logarithm', 'Linear'],
defaultValue: 0,
outputRawData: (val) => {
const scaleArr = ['Logarithm', 'Linear']
return scaleArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const scaleArr = ['Logarithm', 'Linear']
return scaleArr[parseInt(idx)]
},
},
EIS_DELAY: {
type: 'number',
showName: 'DELAY',
componentType: 'input-field',
range: Object.freeze({ min: 0, max: 100 }),
outputRawData: (val) => {
return parseInt(parseFloat(val) * 10)
},
outputReadabilityData: (val) => {
return parseFloat(val / 10).toFixed(1)
},
defaultValue: 0,
defaultUnit: 'points',
downloadUnit: null,
unit: {
points: 1,
},
},
EIS_AVERAGE_NUM: {
type: 'array',
showName: 'Average',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: '2' },
{ value: 1, label: '4' },
{ value: 2, label: '6' },
{ value: 3, label: '8' },
],
range: ['2', '4', '6', '8'],
defaultValue: 0,
outputRawData: (val) => {
const numArr = ['2', '4', '6', '8']
return numArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const numArr = ['2', '4', '6', '8']
return numArr[parseInt(idx)]
},
},
CF_DC_BIAS: {
type: 'number',
showName: 'DC Volt',
componentType: 'input-field',
range: Object.freeze({ min: 2500, max: 50000 }), // UI上能輸入的最大最小值
outputRawData: (val, scale = 1) => {
return Math.round(parseInt(val) * 12.5 * scale + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return Math.round(parseInt(val - 25000) / 12.5) / scale
},
defaultValue: 25000,
defaultUnit: 'mV',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
},
CF_AC_AMP: {
type: 'number',
showName: 'AC Amp',
componentType: 'input-field',
range: Object.freeze({ min: 0, max: 2047 }),
outputRawData: (val, scale = 1) => {
return Math.round((parseInt(val * scale) / 800) * 2047)
},
outputReadabilityData: (val, scale = 1) => {
return Math.round((parseInt(val) / 2047) * 800) / scale
},
defaultValue: 25,
defaultUnit: 'mV',
downloadUnit: 'mV',
unit: {
mV: 1,
},
},
CF_FREQ: {
type: 'number',
showName: 'Frequency',
componentType: 'input-field',
range: Object.freeze({ min: 1, max: 13333333 }),
outputRawData: (val) => {
return parseFloat(val) < 0.1 ? Math.round(0.1 / 0.015) : Math.round(parseFloat(val) / 0.015)
},
outputReadabilityData: (val) => {
return (parseFloat(val) * 0.015).toFixed(1)
},
defaultValue: 13333333,
defaultUnit: 'Hz',
downloadUnit: 'Hz',
unit: {
Hz: 1,
},
},
CF_PPD: {
type: 'number',
showName: 'Points per decades',
componentType: 'input-field',
range: Object.freeze({ min: 1, max: 10 }),
outputRawData: (val) => {
return parseInt(val)
},
outputReadabilityData: (val) => {
return parseInt(val)
},
defaultValue: 10,
defaultUnit: 'points',
downloadUnit: null,
unit: {
points: 1,
},
},
CF_SCALE: {
type: 'array',
showName: 'Point spacing',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: 'Logarithm' },
{ value: 1, label: 'Linear' },
],
range: ['Logarithm', 'Linear'],
defaultValue: 0,
outputRawData: (val) => {
const scaleArr = ['Logarithm', 'Linear']
return scaleArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const scaleArr = ['Logarithm', 'Linear']
return scaleArr[parseInt(idx)]
},
},
CF_DELAY: {
type: 'number',
showName: 'DELAY',
componentType: 'input-field',
range: Object.freeze({ min: 0, max: 100 }),
outputRawData: (val) => {
return parseInt(parseFloat(val) * 10)
},
outputReadabilityData: (val) => {
return parseFloat(val / 10).toFixed(1)
},
defaultValue: 0,
defaultUnit: 'points',
downloadUnit: null,
unit: {
points: 1,
},
},
CF_AVERAGE_NUM: {
type: 'array',
showName: 'Average',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: '2' },
{ value: 1, label: '4' },
{ value: 2, label: '6' },
{ value: 3, label: '8' },
],
range: ['2', '4', '6', '8'],
defaultValue: 3,
outputRawData: (val) => {
const numArr = ['2', '4', '6', '8']
return numArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const numArr = ['2', '4', '6', '8']
return numArr[parseInt(idx)]
},
},
CV_E_INITIAL: {
type: 'number',
showName: 'E-Initial',
componentType: 'input-range',
range: Object.freeze({ min: 2500, max: 50000 }),
outputRawData: (val, scale = 1) => {
return parseInt(parseFloat(val) * scale * 12.5 + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return parseInt((parseFloat(val) - 25000) / 12.5) / scale
},
defaultValue: 25000,
defaultUnit: 'V',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
},
CV_E1: {
type: 'number',
showName: 'E1',
componentType: 'input-range',
range: Object.freeze({ min: 2500, max: 50000 }),
outputRawData: (val, scale = 1) => {
return parseInt(parseFloat(val) * scale * 12.5 + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return parseInt((parseFloat(val) - 25000) / 12.5) / scale
},
defaultValue: 25000,
defaultUnit: 'V',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
},
CV_E2: {
type: 'number',
showName: 'E2',
componentType: 'input-range',
range: Object.freeze({ min: 2500, max: 50000 }),
outputRawData: (val, scale = 1) => {
return parseInt(parseFloat(val) * scale * 12.5 + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return parseInt((parseFloat(val) - 25000) / 12.5) / scale
},
defaultValue: 25000,
defaultUnit: 'V',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
},
CV_SCAN_RATE: {
type: 'number',
showName: 'ScanRate',
componentType: 'input-range',
range: Object.freeze({ min: 1, max: 100000 }),
outputRawData: (val) => {
return parseInt(parseFloat(val) * 100)
},
outputReadabilityData: (val) => {
return parseFloat(val) / 100
},
defaultValue: 10000,
defaultUnit: 'mV/s',
downloadUnit: 'mV/s',
unit: {
'mV/s': 1,
},
},
CA_VOLT: {
type: 'number',
showName: 'Volt (v.s. ref)',
componentType: 'input-range',
range: Object.freeze({ min: 2500, max: 50000 }),
outputRawData: (val, scale = 1) => {
return parseInt(parseFloat(val) * scale * 12.5 + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return parseInt((parseFloat(val) - 25000) / 12.5) / scale
},
defaultValue: 25000,
defaultUnit: 'V',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
},
VT_MEASURE_VIN_RANGE: {
type: 'array',
showName: 'Vin Range',
componentType: 'input-button-toggle',
options: [
{ value: 0, label: '0~2V' },
{ value: 1, label: '-1~1V' },
{ value: 2, label: '-2~0V' },
{ value: 3, label: 'Auto' },
],
range: ['1', '2', '3', 'Auto'],
defaultValue: 0,
outputRawData: (val) => {
const voltageInRangeArr = ['1', '2', '3', 'Auto']
return voltageInRangeArr.indexOf(val.toString())
},
outputReadabilityData: (idx) => {
const voltageInRangeArr = ['1', '2', '3', 'Auto']
return voltageInRangeArr[parseInt(idx)]
},
},
RT_VOLT_SET: {
type: 'number',
showName: 'Volt out',
componentType: 'input-range',
range: Object.freeze({ min: 2500, max: 50000 }),
defaultValue: 37500,
defaultUnit: 'V',
downloadUnit: 'mV',
unit: {
mV: 1,
V: 1e3,
},
outputRawData: (val, scale = 1) => {
return parseInt(parseFloat(val) * scale * 12.5 + 25000)
},
outputReadabilityData: (val, scale = 1) => {
return parseInt((parseFloat(val) - 25000) / 12.5) / scale
},
},
ADC_VALUE_I: {
type: 'none',
showName: 'Instruction',
componentType: 'dev-mode',
},
MODE_OPTIONS: [
{
id: 7,
description: 'Idle',
},
{
id: 0,
description: 'Potentiostatic Electrochemical Impedance Spectroscopy',
},
{
id: 1,
description: 'CV',
},
{
id: 2,
description: 'Chronoamperometry',
},
{
id: 3,
description: 'VT',
},
{
id: 4,
description: 'RT',
},
{
id: 5,
description: 'Constant Frequency',
},
{
id: 6,
description: 'Dev Tools',
},
],
MODE: {
0: PotentiostaticEIS,
1: CyclicVoltammetry,
2: Chronoamperometry,
3: VT,
4: RT,
5: ConstantFrequency,
6: DevMode,
7: Idle,
},
}
export default EliteEIS
+148
View File
@@ -0,0 +1,148 @@
import EliteEDC from './EliteEDC/index'
import EliteEIS from './EliteEIS/index'
// object saving library name mapping table
const libraryNameMappingTable = {
EDC: EliteEDC,
EliteZM15: EliteEDC,
'Elite_EDC_1.4': null,
'Elite_EDC_1.5': EliteEDC,
'Elite_EDC_1.5re': EliteEDC,
'Elite_EDC_1.5r2': EliteEDC,
'Elite_BAT_1.0': EliteEDC,
EIS: EliteEIS,
'Elite_EIS_1.0': EliteEIS,
'Elite_EIS_1.1': EliteEIS,
'Elite_EIS_MINI_1.0': EliteEIS,
'Elite_TRIG_0.1': null,
'Elite_MEGAFLY_0.1': null,
}
// object saving serial number mapping table
const serialNumberMappingTable = {
0: {
2: {
1: {
5: null, // EDC1.4
6: EliteEDC, // EDC1.5
7: EliteEDC, // EDC1.5re
8: EliteEDC, // EDC1.5r2
},
},
3: {
1: {
0: EliteEDC, // BAT1.0
},
},
4: {
1: {
0: EliteEIS, // EIS1.0
1: EliteEIS, // EIS1.1
2: EliteEIS, // EIS1.1mini
},
},
5: {
1: {
0: null, // TRIG0.1
},
},
6: {
1: {
0: null, // MEAGFLY0.1
},
},
},
}
/**
* return config table by library or serial number (type)
* @param {String | Object} type
* @returns {Object} : config
*/
function getConfig(type) {
if (type === undefined || type === null) return
// if (typeof type === 'number') {
// const deviceList = store.getters.getField('taskContent').deviceListNew
// if (deviceList === undefined) return
// const device = deviceList.find((ele) => ele.memory_board === type)
// if (device === undefined) return
// return libraryNameMappingTable[device.library_name]
// }
// library name
if (typeof type === 'string') {
return libraryNameMappingTable[type]
}
// serial number
if (typeof type === 'object') {
return serialNumberMappingTable[type[0]][type[1]][type[2]][type[3]]
}
}
/**
* return mode config table by type and mode
* @param {String | Object} type
* @param {Number} mode
* @returns {Object} : mode-config
*/
function getModeConfig(type, mode) {
return getConfig(type).MODE[mode]
}
/**
* return parameter config table by type and parameter name
* @param {String | Object} type
* @param {String} parameterName
* @returns {Object} : parameter-config
*/
function getParameterConfig(deviceType, parameterName) {
return getConfig(deviceType)[parameterName]
}
/**
* return channel config table by type and mode
* @param {String | Object} type
* @param {String} mode
* @param {String | Number} channel
* @returns {Object} : channel-config
*/
function getChannelConfig(type, mode, channel) {
if (channel === undefined) {
return getModeConfig(type, mode).channels
}
return getModeConfig(type, mode).channels[channel]
}
/**
* return chart config table by type and mode and chartType
* @param {String | Object} type
* @param {String} mode
* @param {String} chartType
* @returns {Object} : chart-config
*/
function getChartConfig(type, mode, chartType = 'default') {
return getModeConfig(type, mode).charts[chartType]
}
/**
* return mode's parameter list
* @param {String | Object} type
* @param {String} mode
* @returns {Object} : parameter list
*/
function getModeParameter(type, mode) {
return getModeConfig(type, mode).parameter
}
const configTable = {
getConfig,
getModeConfig,
getChannelConfig,
getParameterConfig,
getChartConfig,
getModeParameter,
EliteEDC,
EliteEIS,
}
export default configTable
+20
View File
@@ -0,0 +1,20 @@
import { EChartsOption } from 'echarts'
import { generateLegend } from './legend'
import { generateGrid } from './grid'
import { generateXAxis } from './xAxis'
import { generateYAxis } from './yAxis'
import { generateTooltip } from './tooltip'
import { generateSeries } from './series'
import { generateDataZoom } from './datazoom'
export const generateChart = function (): EChartsOption {
return {
legend: generateLegend(),
tooltip: generateTooltip(),
grid: [generateGrid()],
xAxis: [generateXAxis()],
yAxis: [generateYAxis()],
series: [generateSeries('')],
dataZoom: generateDataZoom(),
}
}
+10
View File
@@ -0,0 +1,10 @@
import { ref } from 'vue'
import { ECharts } from 'echarts'
import { generateChart } from '@/data/echart/chart'
export default function lineChart() {
const chart_ref = ref<ECharts | null>(null)
const option = generateChart()
return { option, chart_ref }
}
+20
View File
@@ -0,0 +1,20 @@
import { DataZoomComponentOption } from 'echarts'
export const generateDataZoom = function (): DataZoomComponentOption | DataZoomComponentOption[] {
return [
{
show: true,
realtime: true,
start: 0,
end: 100,
xAxisIndex: [0, 1],
},
{
type: 'inside',
realtime: true,
start: 0,
end: 100,
xAxisIndex: [0, 1],
},
]
}
+5
View File
@@ -0,0 +1,5 @@
import { TooltipComponentFormatterCallbackParams } from 'echarts'
export const generateFormatter = function (params: any): string {
return String(params[0].value)
}
+18
View File
@@ -0,0 +1,18 @@
import { GridComponentOption } from 'echarts'
export const generateGrid = function (): GridComponentOption {
const index = 0
const length = 1
// const chartID = 1
const _height = 82 / length - 2 + '%'
const _top = index * (82 / length) + 1 + '%'
const _left = '8%'
const _right = '8%'
return {
top: _top,
height: _height,
left: _left,
right: _right,
}
}
+14
View File
@@ -0,0 +1,14 @@
import { LegendComponentOption } from 'echarts'
export const generateLegend = function (): LegendComponentOption {
return {
type: 'scroll',
data: [],
// x: 'center',
// y: '-10%',
bottom: '0%',
textStyle: {
color: '#34495e',
},
}
}
+19
View File
@@ -0,0 +1,19 @@
import { MarkLineComponentOption } from 'echarts'
export const generateMarkLine = function (): MarkLineComponentOption {
return {
symbol: ['none', 'none'],
// cannot create empty mark line data
data: [
// {
// name: 'ceiling',
// },
// {
// name: 'ground',
// },
// {
// name: 'middle',
// },
],
}
}
+36
View File
@@ -0,0 +1,36 @@
import { LineSeriesOption } from 'echarts'
import { generateMarkLine } from './markLine'
export const generateSeries = function (name: string): LineSeriesOption {
return {
type: 'line',
name: name || '',
showSymbol: false,
// silent: true,
data: [],
// markLine: {
// data: [
// {
// // 固定起点的 x 像素位置,用于模拟一条指向最大值的水平线
// name: 'test',
// yAxis: '200',
// },
// ],
// },
// xAxisIndex: xAxisIndex,
// yAxisIndex: yAxisIndex,
// AxisSource: [deviceID, channel], use it to get data stream from buffer
// xAxisSource: xAxisSource,
// yAxisSource: yAxisSource,
animation: false,
// dataXMax: null,
// dataXMin: null,
// dataYMax: null,
// dataYMin: null,
// itemStyle: {},
// lineStyle: {
// width: 1.5,
// },
markLine: generateMarkLine(),
}
}
+15
View File
@@ -0,0 +1,15 @@
import { TooltipComponentOption } from 'echarts'
import { generateFormatter } from './formatter'
export const generateTooltip = function (): TooltipComponentOption {
return {
padding: 10,
backgroundColor: '#fff',
borderColor: 'rgba(0, 0, 200, 0.2)',
borderWidth: 1,
borderRadius: 0,
trigger: 'axis',
hideDelay: 5000,
formatter: generateFormatter,
}
}
+35
View File
@@ -0,0 +1,35 @@
import { XAXisComponentOption } from 'echarts'
declare const AXIS_TYPES: {
readonly value: 1
readonly category: 1
readonly time: 1
readonly log: 1
}
declare type OptionAxisType = keyof typeof AXIS_TYPES
export const generateXAxis = function (
type?: OptionAxisType,
gridIndex?: number,
// boundaryGap?: [string | number, string | number],
): XAXisComponentOption {
return {
type: type || 'value',
show: true,
gridIndex: gridIndex || 0,
// scale: true,
// boundaryGap: true,
axisLine: { onZero: false, lineStyle: { color: '#aaa' } },
axisTick: { show: false },
axisLabel: {
show: true,
showMinLabel: false,
showMaxLabel: false,
color: '#34495e',
},
splitLine: { show: true, lineStyle: { color: '#aaa' } },
min: 'dataMin',
max: 'dataMax',
// interval: undefined,
}
}
+35
View File
@@ -0,0 +1,35 @@
import { YAXisComponentOption } from 'echarts'
declare const AXIS_TYPES: {
readonly value: 1
readonly category: 1
readonly time: 1
readonly log: 1
}
declare type OptionAxisType = keyof typeof AXIS_TYPES
export const generateYAxis = function (
type?: OptionAxisType,
gridIndex?: number,
// boundaryGap?: [string | number, string | number],
): YAXisComponentOption {
return {
type: type || 'value',
show: true,
gridIndex: gridIndex || 0,
// scale: true,
// boundaryGap: true,
axisLine: { onZero: false, lineStyle: { color: '#aaa' } },
axisTick: { show: false },
axisLabel: {
show: true,
showMinLabel: false,
showMaxLabel: false,
color: '#34495e',
},
splitLine: { show: true, lineStyle: { color: '#aaa' } },
min: 'dataMin',
max: 'dataMax',
// interval: undefined,
}
}
File diff suppressed because it is too large Load Diff
-342
View File
@@ -1,342 +0,0 @@
import { computed, ComputedRef, Ref } from '@vue/reactivity'
import { useColors } from 'vuestic-ui'
type GeoBounds = {
bottom: number
left: number
right: number
top: number
}
export type PointGeoCoord = {
latitude: number
longitude: number
}
export type DataGeometry = {
geometry: {
type: string
coordinates: [number, number][]
}
}
export type CityItem = {
id?: string
title: string
country: string
latitude: number
longitude: number
svgPath: string
color: string
flights?: PointGeoCoord[]
}
const targetSVG =
'M9,0C4.029,0,0,4.029,0,9s4.029,9,9,9s9-4.029,9-9S13.971,0,9,0z M9,15.93 c-3.83,0-6.93-3.1-6.93-6.93S5.17,2.07,9,2.07s6.93,3.1,6.93,6.93S12.83,15.93,9,15.93 M12.5,9c0,1.933-1.567,3.5-3.5,3.5S5.5,10.933,5.5,9S7.067,5.5,9,5.5 S12.5,7.067,12.5,9z'
export const planeSVG =
'M19.671,8.11l-2.777,2.777l-3.837-0.861c0.362-0.505,0.916-1.683,0.464-2.135c-0.518-0.517-1.979,0.278-2.305,0.604l-0.913,0.913L7.614,8.804l-2.021,2.021l2.232,1.061l-0.082,0.082l1.701,1.701l0.688-0.687l3.164,1.504L9.571,18.21H6.413l-1.137,1.138l3.6,0.948l1.83,1.83l0.947,3.598l1.137-1.137V21.43l3.725-3.725l1.504,3.164l-0.687,0.687l1.702,1.701l0.081-0.081l1.062,2.231l2.02-2.02l-0.604-2.689l0.912-0.912c0.326-0.326,1.121-1.789,0.604-2.306c-0.452-0.452-1.63,0.101-2.135,0.464l-0.861-3.838l2.777-2.777c0.947-0.947,3.599-4.862,2.62-5.839C24.533,4.512,20.618,7.163,19.671,8.11z'
const london = {
id: 'london',
color: 'info',
svgPath: targetSVG,
title: 'London',
country: 'United Kingdom',
latitude: 51.5002,
longitude: -0.1262,
flights: [
{
latitude: 50.4422,
longitude: 30.5367,
},
{
latitude: 46.948,
longitude: 7.4481,
},
{
latitude: 59.3328,
longitude: 18.0645,
},
{
latitude: 40.4167,
longitude: -3.7033,
},
{
latitude: 46.0514,
longitude: 14.506,
},
{
latitude: 48.2116,
longitude: 17.1547,
},
{
latitude: 44.8048,
longitude: 20.4781,
},
{
latitude: 55.7558,
longitude: 37.6176,
},
{
latitude: 38.7072,
longitude: -9.1355,
},
{
latitude: 54.6896,
longitude: 25.2799,
},
{
latitude: 64.1353,
longitude: -21.8952,
},
{
latitude: 40.43,
longitude: -74.0,
},
],
}
const vilnius = {
id: 'vilnius',
color: 'info',
svgPath: targetSVG,
title: 'Vilnius',
country: 'Lithuania',
latitude: 54.6896,
longitude: 25.2799,
flights: [
{
latitude: 50.8371,
longitude: 4.3676,
},
{
latitude: 59.9138,
longitude: 10.7387,
},
{
latitude: 40.4167,
longitude: -3.7033,
},
{
latitude: 50.0878,
longitude: 14.4205,
},
{
latitude: 48.2116,
longitude: 17.1547,
},
{
latitude: 44.8048,
longitude: 20.4781,
},
{
latitude: 55.7558,
longitude: 37.6176,
},
{
latitude: 37.9792,
longitude: 23.7166,
},
{
latitude: 51.5002,
longitude: -0.1262,
},
{
latitude: 53.3441,
longitude: -6.2675,
},
],
}
const cities: CityItem[] = [
london,
vilnius,
{
svgPath: targetSVG,
color: 'info',
title: 'Brussels',
country: 'Belgium',
latitude: 50.8371,
longitude: 4.3676,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Prague',
country: 'Czech Republic',
latitude: 50.0878,
longitude: 14.4205,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Athens',
country: 'Greece',
latitude: 37.9792,
longitude: 23.7166,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Reykjavik',
country: 'Iceland',
latitude: 64.1353,
longitude: -21.8952,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Dublin',
country: 'Ireland',
latitude: 53.3441,
longitude: -6.2675,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Oslo',
country: 'Norway',
latitude: 59.9138,
longitude: 10.7387,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Lisbon',
country: 'Portugal',
latitude: 38.7072,
longitude: -9.1355,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Moscow',
country: 'Russia',
latitude: 55.7558,
longitude: 37.6176,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Belgrade',
country: 'Serbia',
latitude: 44.8048,
longitude: 20.4781,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Bratislava',
country: 'Slovakia',
latitude: 48.2116,
longitude: 17.1547,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Ljubljana',
country: 'Slovenia',
latitude: 46.0514,
longitude: 14.506,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Madrid',
country: 'Spain',
latitude: 40.4167,
longitude: -3.7033,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Stockholm',
country: 'Sweden',
latitude: 59.3328,
longitude: 18.0645,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Bern',
country: 'Switzerland',
latitude: 46.948,
longitude: 7.4481,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Kiev',
country: 'Ukraine',
latitude: 50.4422,
longitude: 30.5367,
},
{
svgPath: targetSVG,
color: 'info',
title: 'Paris',
country: 'France',
latitude: 48.8567,
longitude: 2.351,
},
{
svgPath: targetSVG,
color: 'info',
title: 'New York',
country: 'United States of America',
latitude: 40.43,
longitude: -74,
},
]
export const lineMapData = {
cities,
mainCity: london.title,
homeCity: london.title,
}
export const useMapData = (data: Ref<CityItem[]>): ComputedRef<CityItem[]> => {
const { getColor } = useColors()
return computed(() =>
data.value.map((item) => ({
...item,
color: getColor(item.color),
})),
)
}
export const getGeoBounds = (item?: CityItem): GeoBounds | undefined => {
if (!item || !item.flights || !item.flights.length) {
return
}
const latitudes = [...item.flights.map(({ latitude }) => latitude), item.latitude]
const longitudes = [...item.flights.map(({ longitude }) => longitude), item.longitude]
return {
bottom: Math.min(...latitudes),
left: Math.min(...longitudes),
right: Math.max(...longitudes),
top: Math.max(...latitudes),
}
}
export const generateLineSeriesData = (item?: CityItem): DataGeometry[] | undefined => {
if (!item || !item.flights || !item.flights.length) {
return
}
return item.flights.map((point) => ({
geometry: {
type: 'LineString',
coordinates: [
[item.longitude, item.latitude],
[point.longitude, point.latitude],
],
},
}))
}
export const compareStrings = (first: string, second: string) => first.toLowerCase() === second.toLowerCase()
+29
View File
@@ -0,0 +1,29 @@
import { getAxios } from '@/data/axios'
import { AxiosResponse } from 'axios'
const axios = getAxios()
const FOLDER_TYPE = 'folder'
const getCollection = async function (
parent: number,
offset: number,
limit: number,
order: Array<string>,
): Promise<AxiosResponse<any, any>> {
let url = `api/file/collection/get?type=${FOLDER_TYPE}&`
if (parent) url += `parent=${parent}&`
if (offset) url += `offset=${offset}&`
if (limit) url += `limit=${limit}&`
if (order) {
const _order = order?.join('-')
url += `order=${_order}`
}
const result = await axios.get(url)
return result
}
const meta = {
getCollection,
}
export default meta
+15
View File
@@ -0,0 +1,15 @@
import meta from './meta'
import collection from './collection'
import project from './project'
import subject from './subject'
import subject_data from './subject_data'
const api = {
collection,
meta,
project,
subject,
subject_data,
}
export default api
+72
View File
@@ -0,0 +1,72 @@
import { getAxios } from '@/data/axios'
import { AxiosResponse } from 'axios'
const FOLDER_TYPE = 'folder'
const axios = getAxios()
const getMetaWithTypeFolder = async function (
parent: number,
offset?: number,
limit?: number,
order?: Array<string>,
): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?type=${FOLDER_TYPE}&`
if (parent) url += `parent=${parent}&`
if (offset) url += `offset=${offset}&`
if (limit) url += `limit=${limit}&`
if (order) {
const _order = order?.join('-')
url += `order=${_order}`
}
const result = await axios.get(url)
return result
}
const getMetaByTime = async function (time: string, offset?: number, limit?: number): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?time=${time}`
if (offset !== undefined) url += `&offset=${offset}`
if (limit !== undefined) url += `&limit=${limit}`
// console.log('url', url)
const result = await axios.get(url)
return result
}
const getMetaGroupByTime = async function (offset?: number, limit?: number): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?group=time`
if (offset !== undefined) url += `&offset=${offset}`
if (limit !== undefined) url += `&limit=${limit}`
const result = await axios.get(url)
return result
}
const getMetaByProject = async function (
uuid: string,
offset?: number,
limit?: number,
): Promise<AxiosResponse<any, any>> {
let url = `api/file/meta/get?type=project&project=${uuid}`
if (offset !== undefined) url += `&offset=${offset}`
if (limit !== undefined) url += `&limit=${limit}`
const result = await axios.get(url)
return result
}
const findMeta = async function (id, range) {
let url = `api/file/meta/find?`
if (id !== undefined) url += `id=${JSON.stringify(id)}`
if (range !== undefined) url += `&range=${JSON.stringify(range)}`
const result = await axios.get(url)
return result
}
const meta = {
getMetaWithTypeFolder,
getMetaByTime,
getMetaByProject,
getMetaGroupByTime,
findMeta,
}
export default meta
+17
View File
@@ -0,0 +1,17 @@
import { getAxios } from '@/data/axios'
import { AxiosResponse } from 'axios'
const axios = getAxios()
const getProjectGroup = async function (attrs?: Array<string>): Promise<AxiosResponse<any, any>> {
let url = `api/project/report/get?`
if (attrs) url += `attrs=${attrs.join('-')}`
const result = await axios.get(url)
return result
}
const project = {
getProjectGroup,
}
export default project
+49
View File
@@ -0,0 +1,49 @@
import { getAxios } from '@/data/axios'
import { AxiosResponse } from 'axios'
const axios = getAxios()
async function create(attrs) {
try {
return await axios.post('/api/subject/create', attrs)
} catch (e) {
console.error(e)
return false
}
}
async function update(id, attrs) {
try {
return await axios.post(`/api/subject/update/${id}`, attrs)
} catch (e) {
console.error(e)
return false
}
}
async function clearDel() {
try {
return await axios.get('/api/subject/clear_deleted')
} catch (e) {
console.error(e)
return false
}
}
async function get(id) {
try {
return await axios.get('/api/subject/get')
} catch (e) {
console.error(e)
return false
}
}
const subject = {
create,
update,
clearDel,
get,
}
export default subject
+53
View File
@@ -0,0 +1,53 @@
import { getAxios } from '@/data/axios'
import { AxiosResponse } from 'axios'
const axios = getAxios()
async function create(attrs) {
try {
return await axios.post('/api/subject_data/create', attrs)
} catch (e) {
console.error(e)
return false
}
}
async function update(id, attrs) {
try {
return await axios.post(`/api/subject_data/update/${id}`, attrs)
} catch (e) {
console.error(e)
return false
}
}
async function clearDel() {
try {
return await axios.get('/api/subject_data/clear_deleted')
} catch (e) {
console.error(e)
return false
}
}
async function get(id) {
try {
let query = ''
if (id.subject_id) {
query += `subject_id=${id.subject_id}`
}
return await axios.get('/api/subject_data/get?' + query)
} catch (e) {
console.error(e)
return false
}
}
const subject = {
create,
update,
clearDel,
get,
}
export default subject
-402
View File
@@ -1,402 +0,0 @@
[
{
"id": "5d3026a3a4c8c8f35689104b",
"name": "Mcguire Prince",
"email": "mcguireprince@glasstep.com",
"country": "Swaziland",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3e1579c30d1703632",
"name": "Dean Jennings",
"email": "deanjennings@glasstep.com",
"country": "Korea (North)",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a38023a44a3b5e934d",
"name": "Cotton Weber",
"email": "cottonweber@glasstep.com",
"country": "Mozambique",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a31c6b23082419e5f4",
"name": "Osborne Foster",
"email": "osbornefoster@glasstep.com",
"country": "US Minor Outlying Islands",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a3b2cca1fd45746dbf",
"name": "William Dillard",
"email": "williamdillard@glasstep.com",
"country": "Cayman Islands",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3486badb41f9f18b5",
"name": "Anna Meyers",
"email": "annameyers@glasstep.com",
"country": "Viet Nam",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3c614901a53477e5c",
"name": "Ana Barrett",
"email": "anabarrett@glasstep.com",
"country": "Rwanda",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3fcff2a76b73e6016",
"name": "Pam Ward",
"email": "pamward@glasstep.com",
"country": "Kuwait",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3b54fc3e9a2570ce8",
"name": "Hannah Holloway",
"email": "hannahholloway@glasstep.com",
"country": "Gibraltar",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3e2303324ae9d823f",
"name": "Allison Cobb",
"email": "allisoncobb@glasstep.com",
"country": "East Timor",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3f22a52e3706ed868",
"name": "Terrie Hawkins",
"email": "terriehawkins@glasstep.com",
"country": "Greenland",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a32bad267623e706ec",
"name": "Peck Ryan",
"email": "peckryan@glasstep.com",
"country": "Belgium",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a37a50452a85d01cbb",
"name": "Candace Powell",
"email": "candacepowell@glasstep.com",
"country": "Yugoslavia",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3ce9f5acf20065037",
"name": "Wolfe Pitts",
"email": "wolfepitts@glasstep.com",
"country": "Bouvet Island",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a3e3a5afe09338eca5",
"name": "Marietta Robbins",
"email": "mariettarobbins@glasstep.com",
"country": "Martinique",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a33fc3196e598bdc7b",
"name": "Michelle Wolfe",
"email": "michellewolfe@glasstep.com",
"country": "French Guiana",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3364f517d8f5dbf16",
"name": "Katina Lindsay",
"email": "katinalindsay@glasstep.com",
"country": "Guyana",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a313dedc3cf25404ba",
"name": "Bridgett Lloyd",
"email": "bridgettlloyd@glasstep.com",
"country": "Niger",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3a72281322b845f6a",
"name": "Letha Hamilton",
"email": "lethahamilton@glasstep.com",
"country": "Zimbabwe",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3bd037e491b76f097",
"name": "Mcclain Doyle",
"email": "mcclaindoyle@glasstep.com",
"country": "Switzerland",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a36aa5b7fda077d6ef",
"name": "Giles Lucas",
"email": "gileslucas@glasstep.com",
"country": "Bhutan",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a381c974954ce9ab94",
"name": "Figueroa Lowery",
"email": "figueroalowery@glasstep.com",
"country": "Netherlands Antilles",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3c0af2698fcd2a750",
"name": "Valeria Justice",
"email": "valeriajustice@glasstep.com",
"country": "Moldova",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a301d5e7c957e6d864",
"name": "Louise Ayala",
"email": "louiseayala@glasstep.com",
"country": "India",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a31f6f1fd6399aeee6",
"name": "Kathrine Kirby",
"email": "kathrinekirby@glasstep.com",
"country": "Cook Islands",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3e8cb16cd2afa41dd",
"name": "Brandi Morris",
"email": "brandimorris@glasstep.com",
"country": "Honduras",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a3c52ac7ffb85c892d",
"name": "Margaret Mckenzie",
"email": "margaretmckenzie@glasstep.com",
"country": "Jordan",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3c66670f258790358",
"name": "Janie Collier",
"email": "janiecollier@glasstep.com",
"country": "Samoa",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a3108b6b1d543fb117",
"name": "Catherine Vance",
"email": "catherinevance@glasstep.com",
"country": "Sierra Leone",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a325d727b6d9b85d84",
"name": "Kate Allen",
"email": "kateallen@glasstep.com",
"country": "France",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a32be6debb7532cc75",
"name": "Jeanne Cross",
"email": "jeannecross@glasstep.com",
"country": "Anguilla",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3cc16b4cd36e3a7b4",
"name": "Stewart Hanson",
"email": "stewarthanson@glasstep.com",
"country": "Western Sahara",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3d3496dd200d5f6af",
"name": "Beulah Castaneda",
"email": "beulahcastaneda@glasstep.com",
"country": "Malaysia",
"starred": true,
"status": "rejected"
},
{
"id": "5d3026a3187e74fcd18a7918",
"name": "Carissa Taylor",
"email": "carissataylor@glasstep.com",
"country": "Burkina Faso",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a32db20d8ce9111367",
"name": "Muriel Butler",
"email": "murielbutler@glasstep.com",
"country": "Pitcairn",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a35b04715a89693024",
"name": "Janna Anthony",
"email": "jannaanthony@glasstep.com",
"country": "Nigeria",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3a40b0f908cf0b831",
"name": "Cortez Singleton",
"email": "cortezsingleton@glasstep.com",
"country": "Morocco",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a30ab099fe57fe76ad",
"name": "Acevedo Blevins",
"email": "acevedoblevins@glasstep.com",
"country": "Turkmenistan",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a39f9244d7f7d7fe80",
"name": "Hamilton Lewis",
"email": "hamiltonlewis@glasstep.com",
"country": "Marshall Islands",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a3637724139b82f9bc",
"name": "Marylou Wright",
"email": "marylouwright@glasstep.com",
"country": "Iraq",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a3e5cda49e94e1f0de",
"name": "Lenore Bullock",
"email": "lenorebullock@glasstep.com",
"country": "El Salvador",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a30bcb1168afa7bb26",
"name": "Enid Stephens",
"email": "enidstephens@glasstep.com",
"country": "Greece",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a34b33074f1ee12e73",
"name": "Oneill Joyner",
"email": "oneilljoyner@glasstep.com",
"country": "Micronesia",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a3f3f5a4121051c6bc",
"name": "Kristine Finley",
"email": "kristinefinley@glasstep.com",
"country": "Uganda",
"starred": false,
"status": "paid"
},
{
"id": "5d3026a341bb45b14a38d0ec",
"name": "York Carson",
"email": "yorkcarson@glasstep.com",
"country": "Cyprus",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a32ed6a9a296e01c71",
"name": "Nikki Conway",
"email": "nikkiconway@glasstep.com",
"country": "Tuvalu",
"starred": true,
"status": "paid"
},
{
"id": "5d3026a32b3f710cb8b73bca",
"name": "Lindsey Burgess",
"email": "lindseyburgess@glasstep.com",
"country": "Mali",
"starred": false,
"status": "processing"
},
{
"id": "5d3026a3fbfadf6c0b971769",
"name": "Love Christian",
"email": "lovechristian@glasstep.com",
"country": "Andorra",
"starred": false,
"status": "rejected"
},
{
"id": "5d3026a35c48c5e49f1930e0",
"name": "Julia Sawyer",
"email": "juliasawyer@glasstep.com",
"country": "Hungary",
"starred": true,
"status": "processing"
},
{
"id": "5d3026a3fc275278bd752b31",
"name": "Mayer Warren",
"email": "mayerwarren@glasstep.com",
"country": "Latvia",
"starred": false,
"status": "rejected"
}
]
-13
View File
@@ -1,13 +0,0 @@
import type { TChartData as ChartData } from 'vue-chartjs/dist/types'
export type ColorThemes = {
[key: string]: string
}
export type TLineChartData = ChartData<'line'>
export type TBarChartData = ChartData<'bar'>
export type TBubbleChartData = ChartData<'bubble'>
export type TDoughnutChartData = ChartData<'doughnut'>
export type TPieChartData = ChartData<'pie'>
export type TChartData = TLineChartData | TBarChartData | TBubbleChartData | TDoughnutChartData | TPieChartData
-386
View File
@@ -1,386 +0,0 @@
[
{
"id": "5d2c865e9a0bae79a6ef7cfa",
"firstName": "Ashley",
"lastName": "Mcdaniel",
"fullName": "Ashley Mcdaniel",
"email": "ashleymcdaniel@nebulean.com",
"country": "Cayman Islands",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ec73341e16e5f2251",
"firstName": "Sellers",
"lastName": "Todd",
"fullName": "Todd Sellers",
"email": "sellerstodd@nebulean.com",
"country": "Togo",
"starred": false,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "none",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e38800c5ce28f2f6b",
"firstName": "Sherman",
"lastName": "Knowles",
"fullName": "Sherman Knowles",
"email": "shermanknowles@nebulean.com",
"country": "Central African Republic",
"starred": true,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "none",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e957cd150b82e17a6",
"firstName": "Vasquez",
"lastName": "Lawson",
"fullName": "Vasquez Lawson",
"email": "vasquezlawson@nebulean.com",
"country": "Bouvet Island",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e9194dbe2faf99227",
"firstName": "April",
"lastName": "Sykes",
"fullName": "April Sykes",
"email": "aprilsykes@nebulean.com",
"country": "Saint Vincent and The Grenadines",
"starred": false,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e1ed74d83f6b26934",
"firstName": "Hodges",
"lastName": "Garrison",
"fullName": "Hodges Garrison",
"email": "hodgesgarrison@nebulean.com",
"country": "Zimbabwe",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "none",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e0ef31380880c3de5",
"firstName": "Therese",
"lastName": "Stokes",
"fullName": "Therese Stokes",
"email": "theresestokes@nebulean.com",
"country": "Mali",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e4b5ab4727e5c8b69",
"firstName": "Goodwin",
"lastName": "Brewer",
"fullName": "Goodwin Brewer",
"email": "goodwinbrewer@nebulean.com",
"country": "Iraq",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "none",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e4c4d675787cfe1c0",
"firstName": "Gomez",
"lastName": "Wise",
"fullName": "Gomez Wise",
"email": "gomezwise@nebulean.com",
"country": "Portugal",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "none",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e1017c3229017fc68",
"firstName": "Laverne",
"lastName": "Ayers",
"fullName": "Laverne Ayers",
"email": "laverneayers@nebulean.com",
"country": "Micronesia",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ee66676fd7464f8b9",
"firstName": "Stewart",
"lastName": "Leon",
"fullName": "Stewart Leon",
"email": "stewartleon@nebulean.com",
"country": "Seychelles",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e644d8acbed1e0e97",
"firstName": "Lindsey",
"lastName": "Hopkins",
"fullName": "Lindsey Hopkins",
"email": "lindseyhopkins@nebulean.com",
"country": "Costa Rica",
"starred": false,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865ef2b732c74dc3d6a2",
"firstName": "Head",
"lastName": "Lloyd",
"fullName": "Head Lloyd",
"email": "headlloyd@nebulean.com",
"country": "Turkey",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e4ee4f09e92ead2e7",
"firstName": "Fisher",
"lastName": "Bradford",
"fullName": "Fisher Bradford",
"email": "fisherbradford@nebulean.com",
"country": "Ethiopia",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e88d46a9e9049a549",
"firstName": "Aurora",
"lastName": "Bird",
"fullName": "Aurora Bird",
"email": "aurorabird@nebulean.com",
"country": "Burkina Faso",
"starred": false,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e44bf14ea96d6e752",
"firstName": "Bonita",
"lastName": "Shields",
"fullName": "Bonita Shields",
"email": "bonitashields@nebulean.com",
"country": "Cote D'Ivoire (Ivory Coast)",
"starred": true,
"hasReport": true,
"status": "warning",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e2a8be26f6ac4369c",
"firstName": "Ethel",
"lastName": "Underwood",
"fullName": "Ethel Underwood",
"email": "ethelunderwood@nebulean.com",
"country": "Vanuatu",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e5e0aea40111c37f8",
"firstName": "Parker",
"lastName": "May",
"fullName": "Parker May",
"email": "parkermay@nebulean.com",
"country": "Pakistan",
"starred": true,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e7e0c05ecc2d0c186",
"firstName": "Hillary",
"lastName": "Waters",
"fullName": "Hillary Waters",
"email": "hillarywaters@nebulean.com",
"country": "Comoros",
"starred": true,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "down",
"color": "primary",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e80a72eeda016b169",
"firstName": "Raquel",
"lastName": "Ferrell",
"fullName": "Raquel Ferrell",
"email": "raquelferrell@nebulean.com",
"country": "China",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "down",
"color": "info",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865eafacadd378add679",
"firstName": "Pickett",
"lastName": "Page",
"fullName": "Pickett Page",
"email": "pickettpage@nebulean.com",
"country": "Bermuda",
"starred": true,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865e772b1a75bb0a07b5",
"firstName": "Alyson",
"lastName": "Bailey",
"fullName": "Alyson Bailey",
"email": "alysonbailey@nebulean.com",
"country": "United Arab Emirates",
"starred": false,
"hasReport": false,
"status": "warning",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 20 C 10 5, 15 5, 30 30 S 20 20, 70 20",
"graphColor": "#4ae387"
},
{
"id": "5d2c865e137c19a76b56210c",
"firstName": "Farley",
"lastName": "Meyers",
"fullName": "Farley Meyers",
"email": "farleymeyers@nebulean.com",
"country": "Christmas Island",
"starred": false,
"hasReport": false,
"status": "info",
"checked": false,
"trend": "up",
"color": "warning",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
},
{
"id": "5d2c865eb0ba37a27aa9afe0",
"firstName": "Hinton",
"lastName": "Avery",
"fullName": "Hinton Avery",
"email": "hintonavery@nebulean.com",
"country": "Liechtenstein",
"starred": false,
"hasReport": true,
"status": "info",
"checked": false,
"trend": "up",
"color": "info",
"graph": "M 5 30 C 10 5, 30 10, 40 30 S 30 30, 90 40",
"graphColor": "#e34a4a"
}
]
+53 -1
View File
@@ -7,7 +7,52 @@ import stores from './stores'
import router from './router' import router from './router'
import vuesticGlobalConfig from './services/vuestic-ui/global-config' import vuesticGlobalConfig from './services/vuestic-ui/global-config'
import App from './App.vue' import App from './App.vue'
import 'virtual:windi.css' import 'virtual:uno.css'
import 'material-icons/iconfont/material-icons.css'
// import Plotly from 'plotly.js-dist-min'
// import ECharts modules
import ECharts from 'vue-echarts'
import { use } from 'echarts/core'
// import ECharts modules manually to reduce bundle size
import { CanvasRenderer } from 'echarts/renderers'
import { LineChart, BarChart, PieChart } from 'echarts/charts'
import {
TitleComponent,
LegendComponent,
GridComponent,
TooltipComponent,
DataZoomComponent,
MarkLineComponent,
ToolboxComponent,
BrushComponent,
} from 'echarts/components'
use([
CanvasRenderer,
LineChart,
PieChart,
BarChart,
GridComponent,
TooltipComponent,
TitleComponent,
LegendComponent,
DataZoomComponent,
ToolboxComponent,
BrushComponent,
MarkLineComponent,
])
import serverApi from '@/data/server-api'
import Slideout from '@hyjiacan/vue-slideout'
import '@hyjiacan/vue-slideout/dist/slideout.css'
import VueGoodTable from 'vue-good-table-next'
import 'vue-good-table-next/dist/vue-good-table-next.css'
import contextmenu from 'v-contextmenu'
import 'v-contextmenu/dist/themes/default.css'
const app = createApp(App) const app = createApp(App)
@@ -15,6 +60,13 @@ app.use(stores)
app.use(router) app.use(router)
app.use(i18n) app.use(i18n)
app.use(createVuestic({ config: vuesticGlobalConfig })) app.use(createVuestic({ config: vuesticGlobalConfig }))
app.use(Slideout)
app.use(VueGoodTable)
app.use(contextmenu)
app.component('EChart', ECharts)
app.provide('server-api', serverApi)
if (import.meta.env.VITE_APP_GTM_ENABLED) { if (import.meta.env.VITE_APP_GTM_ENABLED) {
app.use( app.use(
-50
View File
@@ -1,50 +0,0 @@
<template>
<div class="dashboard">
<dashboard-charts />
<dashboard-info-block />
<div class="row row-equal">
<div class="flex xs12 lg6">
<dashboard-tabs @submit="addAddressToMap" />
</div>
<div class="flex xs12 lg6">
<DashboardMap ref="dashboardMap" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import DashboardCharts from './DashboardCharts.vue'
import DashboardInfoBlock from './DashboardInfoBlock.vue'
import DashboardTabs from './DashboardTabs.vue'
import DashboardMap from './DashboardMap.vue'
const dashboardMap = ref()
function addAddressToMap({ city, country }: { city: { text: string }; country: string }) {
dashboardMap.value.addAddress({ city: city.text, country })
}
</script>
<style lang="scss">
.row-equal .flex {
.va-card {
height: 100%;
}
}
.dashboard {
.va-card {
margin-bottom: 0 !important;
&__title {
display: flex;
justify-content: space-between;
}
}
}
</style>
@@ -1,101 +0,0 @@
<template>
<div class="row row-equal">
<div class="flex xs12 lg6 xl6">
<va-card v-if="lineChartDataGenerated">
<va-card-title>
<h1>{{ t('dashboard.charts.trendyTrends') }}</h1>
<div>
<va-button
class="ma-1"
size="small"
color="danger"
:disabled="datasetIndex === minIndex"
@click="setDatasetIndex(datasetIndex - 1)"
>
{{ t('dashboard.charts.showInLessDetail') }}
</va-button>
<va-button
class="ma-1"
size="small"
color="danger"
:disabled="datasetIndex === maxIndex - 1"
@click="setDatasetIndex(datasetIndex + 1)"
>
{{ t('dashboard.charts.showInMoreDetail') }}
</va-button>
</div>
</va-card-title>
<va-card-content>
<va-chart class="chart" :data="lineChartDataGenerated" type="line" />
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 lg3 xl3">
<va-card class="d-flex">
<va-card-title>
<h1>{{ t('dashboard.charts.loadingSpeed') }}</h1>
<va-button icon="print" plain @click="printChart" />
</va-card-title>
<va-card-content v-if="doughnutChartDataGenerated">
<va-chart ref="doughnutChart" class="chart chart--donut" :data="doughnutChartDataGenerated" type="doughnut" />
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 lg3 xl3">
<dashboard-contributors-chart />
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { doughnutChartData, lineChartData } from '../../../data/charts'
import { useChartData } from '../../../data/charts/composables/useChartData'
import { usePartOfChartData } from './composables/usePartOfChartData'
import VaChart from '../../../components/va-charts/VaChart.vue'
import DashboardContributorsChart from './DashboardContributorsList.vue'
const { t } = useI18n()
const doughnutChart = ref()
const dataGenerated = useChartData(lineChartData, 0.7)
const doughnutChartDataGenerated = useChartData(doughnutChartData)
const {
dataComputed: lineChartDataGenerated,
minIndex,
maxIndex,
datasetIndex,
setDatasetIndex,
} = usePartOfChartData(dataGenerated)
function printChart() {
const windowObjectReference = window.open('', 'Print', 'height=600,width=800') as Window
const img = windowObjectReference.document.createElement('img')
img.src = `${(document.querySelector('.chart--donut canvas') as HTMLCanvasElement | undefined)?.toDataURL(
'image/png',
)}`
img.onload = () => {
windowObjectReference?.document.body.appendChild(img)
}
windowObjectReference.print()
windowObjectReference.onafterprint = () => {
windowObjectReference?.close()
}
}
</script>
<style scoped>
.chart {
height: 400px;
}
</style>
@@ -1,95 +0,0 @@
<template>
<va-card class="d-flex dashboard-contributors-list">
<va-card-title>
<h1>{{ t('dashboard.charts.topContributors') }}</h1>
<div class="mr-0 va-text-right">
<a class="mr-0 va-link" :disabled="contributors.length <= step" @click="showNext">
{{ t('dashboard.charts.showNextFive') }}
</a>
</div>
</va-card-title>
<va-card-content>
<va-inner-loading :loading="loading" style="width: 100%">
<div v-for="(contributor, idx) in visibleList" :key="idx" class="mb-3">
<va-progress-bar :model-value="getPercent(contributor.contributions)" :color="getProgressBarColor(idx)">
{{ contributor.contributions }} {{ t('dashboard.charts.commits') }}
</va-progress-bar>
<p class="mt-2">{{ contributor.login }}</p>
</div>
</va-inner-loading>
</va-card-content>
</va-card>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import axios from 'axios'
const { t } = useI18n()
interface IContributor {
contributions: number
login: string
}
const contributors = ref<IContributor[]>([])
const loading = ref(false)
const progressMax = ref(392)
const visibleList = ref<IContributor[]>([])
const step = ref(5)
const page = ref(0)
onMounted(() => {
loadContributorsList()
})
async function loadContributorsList() {
loading.value = true
const { data } = await axios.get<IContributor[]>(
'https://api.github.com/repos/epicmaxco/vuestic-admin/contributors',
)
contributors.value = data
progressMax.value = Math.max(...contributors.value.map(({ contributions }) => contributions))
showNext()
loading.value = false
}
function getPercent(val: number) {
return (val / progressMax.value) * 100
}
function showNext() {
visibleList.value = contributors.value.slice(page.value * step.value, page.value * step.value + step.value)
page.value += 1
const maxPages = (contributors.value.length - 1) / step.value
if (page.value > maxPages) {
page.value = 0
}
}
function getProgressBarColor(idx: number) {
const themeColors = ['primary', 'success', 'info', 'danger', 'warning']
if (idx < themeColors.length) {
return themeColors[idx]
}
// Get random color if idx out of colors array
const keys = Object.keys(themeColors)
return themeColors[keys[(keys.length * Math.random()) << 0] as unknown as number]
}
</script>
<style scoped lang="scss">
.dashboard-contributors-list {
flex-direction: column;
.inner-loading {
height: 100%;
}
}
</style>
@@ -1,145 +0,0 @@
<template>
<div class="row row-equal">
<div class="flex xl6 xs12 lg6">
<div class="row">
<div v-for="(info, idx) in infoTiles" :key="idx" class="flex xs12 sm4">
<va-card class="mb-4" :color="info.color">
<va-card-content>
<h2 class="va-h2 ma-0" style="color: white">{{ info.value }}</h2>
<p style="color: white">{{ t('dashboard.info.' + info.text) }}</p>
</va-card-content>
</va-card>
</div>
</div>
<div class="row">
<div class="flex xs12 sm6 md6">
<va-card>
<va-card-content>
<h2 class="va-h2 ma-0" :style="{ color: colors.primary }">291</h2>
<p class="no-wrap">{{ t('dashboard.info.completedPullRequests') }}</p>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6">
<va-card>
<va-card-content>
<div class="row row-separated">
<div class="flex xs4">
<h2 class="va-h2 ma-0 va-text-center" :style="{ color: colors.primary }">3</h2>
<p class="va-text-center">{{ t('dashboard.info.users') }}</p>
</div>
<div class="flex xs4">
<h2 class="va-h2 ma-0 va-text-center" :style="{ color: colors.info }">24</h2>
<p class="va-text-center no-wrap">{{ t('dashboard.info.points') }}</p>
</div>
<div class="flex xs4">
<h2 class="va-h2 ma-0 va-text-center" :style="{ color: colors.warning }">91</h2>
<p class="va-text-center">{{ t('dashboard.info.units') }}</p>
</div>
</div>
</va-card-content>
</va-card>
</div>
</div>
</div>
<div class="flex xs12 sm6 md6 xl3 lg3">
<va-card stripe stripe-color="info">
<va-card-title>
{{ t('dashboard.info.componentRichTheme') }}
</va-card-title>
<va-card-content>
<p class="rich-theme-card-text">
Buying the right telescope to take your love of astronomy to the next level is a big next step.
</p>
<div class="mt-3">
<va-button color="primary" target="_blank" href="https://github.com/epicmaxco/vuestic-ui">
{{ t('dashboard.info.viewLibrary') }}
</va-button>
</div>
</va-card-content>
</va-card>
</div>
<div class="flex xs12 sm6 md6 xl3 lg3">
<va-card>
<va-image :src="images[currentImageIndex]" style="height: 200px" />
<va-card-title>
<va-button preset="plain" icon-right="fa-arrow-circle-right" @click="showModal">
{{ t('dashboard.info.exploreGallery') }}
</va-button>
</va-card-title>
</va-card>
</div>
<va-modal v-model="modal">
<va-carousel v-model="currentImageIndex" :items="images" class="gallery-carousel" />
</va-modal>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { VaCarousel, VaModal, VaCard, VaCardContent, VaCardTitle, VaButton, VaImage, useColors } from 'vuestic-ui'
const { t } = useI18n()
const { colors } = useColors()
const infoTiles = ref([
{
color: 'success',
value: '803',
text: 'commits',
icon: '',
},
{
color: 'danger',
value: '57',
text: 'components',
icon: '',
},
{
color: 'info',
value: '5',
text: 'teamMembers',
icon: '',
},
])
const modal = ref(false)
const currentImageIndex = ref(0)
const images = ref([
'https://i.imgur.com/qSykGko.jpg',
'https://i.imgur.com/jYwT08D.png',
'https://i.imgur.com/9930myH.jpg',
'https://i.imgur.com/2JxhWD6.jpg',
'https://i.imgur.com/MpiOWbM.jpg',
])
function showModal() {
modal.value = true
}
</script>
<style lang="scss" scoped>
.row-separated {
.flex + .flex {
border-left: 1px solid var(--va-background-primary);
}
}
.rich-theme-card-text {
line-height: 1.5;
}
.gallery-carousel {
width: 80vw;
max-width: 100%;
@media all and (max-width: 576px) {
width: 100%;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More