Skip to content

Commit e2ecf57

Browse files
authored
Add support for imperial units (#35)
* Add imperial unit support in Config view * Improve imperial chart loading speed * Redraw plots when unit changed, add units info tooltip * Bump version * Fix config input fields not showing on first render when using imperial units * Convert non-saved imperial values * Detect changes to fields in case imperial units are used * Maintain scroll position when unit system is changed on Home view * Fix charts scroll bug * Change units switch info hover text
1 parent 1ee3d23 commit e2ecf57

File tree

9 files changed

+652
-217
lines changed

9 files changed

+652
-217
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cats-configurator",
3-
"version": "0.3.6",
3+
"version": "0.3.7",
44
"private": true,
55
"scripts": {
66
"start": "vue-cli-service electron:serve",

src/components/NavigationPanel.vue

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
<template>
2-
<v-navigation-drawer app dark clipped permanent width="300">
2+
<v-navigation-drawer app dark clipped permanent width="300" class="navigation-panel pb-4">
33
<v-alert v-if="!active" dense text type="info" class="mx-2 mt-2 caption">
4-
Plug in CATS board and connect to activate this panel.
4+
Plug in CATS board and connect to activate this area.
55
</v-alert>
6-
<v-alert
7-
v-if="changedTab"
8-
dense
9-
text
10-
type="warning"
11-
class="mx-2 mt-2 caption"
12-
>
6+
<v-alert v-if="changedTab" dense text type="warning" class="mx-2 mt-2 caption">
137
<div class="d-flex justify-space-between align-center">
148
<div>Unsaved changes.</div>
159
<v-btn small text @click="discard">discard</v-btn>
@@ -26,6 +20,7 @@
2620
</v-list-item-group>
2721
</v-list>
2822
</v-card>
23+
<UnitSwitch class="unit-switch mb-2" />
2924
</v-navigation-drawer>
3025
</template>
3126

@@ -35,9 +30,13 @@ import { getConfigs } from "@/services/configService";
3530
import { getEvents } from "@/services/eventService";
3631
import { getTimers } from "@/services/timerService";
3732
import { getLogData } from "@/services/logService";
33+
import UnitSwitch from "./UnitSwitch.vue";
3834
3935
export default {
4036
name: "NavigationPanel",
37+
components: {
38+
UnitSwitch,
39+
},
4140
props: {
4241
items: {
4342
type: Array,
@@ -71,4 +70,13 @@ export default {
7170
};
7271
</script>
7372

74-
<style></style>
73+
<style scoped>
74+
.navigation-panel ::v-deep .v-navigation-drawer__content {
75+
display: flex;
76+
flex-direction: column;
77+
}
78+
79+
.unit-switch {
80+
margin-top: auto;
81+
}
82+
</style>

src/components/UnitSwitch.vue

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<template>
2+
<v-container class="py-0">
3+
<v-row align="center" justify="start">
4+
<v-col cols="auto">
5+
<v-switch v-model="useImperialUnitsState" label="Use imperial units" hide-details inset class="mt-0 pt-0"
6+
color="primary"></v-switch>
7+
</v-col>
8+
<v-tooltip top>
9+
<template v-slot:activator="{ on, attrs }">
10+
<v-icon
11+
color="primary"
12+
v-on="on"
13+
v-bind="attrs"
14+
>
15+
mdi-information-variant-box-outline
16+
</v-icon>
17+
</template>
18+
<span>Flight Computer natively uses metric units; Imperial values will be converted to the nearest metric integer.</span>
19+
</v-tooltip>
20+
</v-row>
21+
</v-container>
22+
</template>
23+
24+
<script>
25+
import { mapGetters, mapActions } from 'vuex';
26+
27+
export default {
28+
name: 'UnitSwitch',
29+
computed: {
30+
...mapGetters(['useImperialUnits']),
31+
useImperialUnitsState: {
32+
get() {
33+
return this.useImperialUnits;
34+
},
35+
set(newValue) {
36+
this.toggleUnitSystem();
37+
}
38+
}
39+
},
40+
methods: {
41+
...mapActions(['toggleUnitSystem']),
42+
}
43+
};
44+
</script>
45+
46+
<style scoped>
47+
/* These styles help align the switch better within its container */
48+
.v-input--switch.mt-0 {
49+
margin-top: 0 !important;
50+
}
51+
52+
.v-input--switch.pt-0 {
53+
padding-top: 0 !important;
54+
}
55+
56+
/* You can adjust margin-right if the label is too close to the switch thumb */
57+
.v-input--switch .v-label {
58+
margin-right: 8px;
59+
}
60+
</style>

src/modules/plots.js

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
11
import Plotly from 'plotly.js-dist';
2+
import { getDisplayValue } from "@/utils/unitConversions.js";
23

34
const COLOR = "rgb(100, 100, 100)"
45
const EVENT_MAP = {
5-
0: { name: "ev_moving", color: COLOR },
6-
1: { name: "ev_ready", color: COLOR },
7-
2: { name: "ev_liftoff", color: COLOR },
8-
3: { name: "ev_burnout", color: COLOR },
9-
4: { name: "ev_apogee", color: COLOR },
10-
5: { name: "ev_main_deployment", color: COLOR },
11-
6: { name: "ev_touchdown", color: COLOR },
12-
7: { name: "ev_custom1", color: COLOR },
13-
8: { name: "ev_custom2", color: COLOR },
6+
0: { name: "ev_moving", color: COLOR },
7+
1: { name: "ev_ready", color: COLOR },
8+
2: { name: "ev_liftoff", color: COLOR },
9+
3: { name: "ev_burnout", color: COLOR },
10+
4: { name: "ev_apogee", color: COLOR },
11+
5: { name: "ev_main_deployment", color: COLOR },
12+
6: { name: "ev_touchdown", color: COLOR },
13+
7: { name: "ev_custom1", color: COLOR },
14+
8: { name: "ev_custom2", color: COLOR },
1415
}
1516

17+
function adaptTraceNameForConverterFunction(name) {
18+
if (name === 'height') return 'altitude';
19+
if (name === 'Ax') return 'acceleration';
20+
if (name === 'Ay') return 'acceleration';
21+
if (name === 'Az') return 'acceleration';
22+
if (name === 'T') return 'temperature';
23+
if (name === 'P') return 'pressure';
24+
if (name === 'filteredAltitudeAGL') return 'altitude';
25+
return name;
26+
}
27+
28+
const TRACES_TO_CONVERT = ['height', 'acceleration', 'velocity', 'Ax', 'Ay', 'Az', 'T', 'P', 'filteredAltitudeAGL'];
1629

17-
function makePlot(data, elementId, title, ylabel, traceNames, eventInfo) {
30+
function makePlot(data, elementId, title, ylabel, traceNames, eventInfo, useImperialUnits) {
1831

1932
let lines = []
2033
let x = []
@@ -27,6 +40,16 @@ function makePlot(data, elementId, title, ylabel, traceNames, eventInfo) {
2740
})
2841
}
2942
}
43+
44+
if (useImperialUnits) {
45+
data = structuredClone(data)
46+
for (const o of data) {
47+
for (let key of traceNames.filter(value => TRACES_TO_CONVERT.includes(value))) {
48+
o[key] = getDisplayValue(o[key], adaptTraceNameForConverterFunction(key));
49+
}
50+
}
51+
}
52+
3053
for (const o of data) {
3154
let i = 0;
3255
for (let key of traceNames) {
@@ -43,10 +66,10 @@ function makePlot(data, elementId, title, ylabel, traceNames, eventInfo) {
4366
elementId,
4467
lines,
4568
{
46-
title: { text: title},
69+
title: { text: title },
4770
margin: { t: 50 },
4871
xaxis: { title: "Timestamp [s]" },
49-
yaxis: { title: ylabel },
72+
yaxis: { title: ylabel, tickFormat: ',.0f' },
5073
shapes: eventInfo.shapes,
5174
annotations: eventInfo.annotations,
5275
template: 'plotly_dark',
@@ -199,43 +222,44 @@ function makeEventInfoTraces(flightlog) {
199222
return { shapes: shapes, annotations: annotations }
200223
}
201224

202-
export function makePlots(flightlog, element) {
225+
export function makePlots(flightlog, element, useImperialUnits) {
203226
let eventInfo = makeEventInfoTraces(flightlog)
204227

205228
element.replaceChildren([])
206229

207230
let el = document.createElement("div")
208-
document.create
209231
element.append(el)
210-
makePlot(flightlog.flightInfo, el, "State Estimation - Altitude", "Altitude [m]", ["height"], eventInfo)
232+
const altitudeYLabel = useImperialUnits ? "Altitude [ft]" : "Altitude [m]"
233+
makePlot(flightlog.flightInfo, el, "State Estimation - Altitude", altitudeYLabel, ["height"], eventInfo, useImperialUnits)
211234

212235
el = document.createElement("div")
213236
element.append(el)
214-
makePlot(flightlog.flightInfo, el, "State Estimation - Velocity", "Velocity [m/s]", ["velocity"], eventInfo)
215-
216-
// el = document.createElement("div")
217-
// element.append(el)
218-
// makePlot(flightlog.flightInfo, el, "Acceleration [m/s^2]", ["acceleration"], eventInfo)
237+
const velocityYLabel = useImperialUnits ? "Velocity [ft/s]" : "Velocity [m/s]"
238+
makePlot(flightlog.flightInfo, el, "State Estimation - Velocity", velocityYLabel, ["velocity"], eventInfo, useImperialUnits)
219239

220240
el = document.createElement("div")
221241
element.append(el)
222-
makePlot(flightlog.imu, el, "IMU - Acceleration", "Acceleration [m/s^2]", ["Ax", "Ay", "Az"], eventInfo)
242+
const accelerationYLabel = useImperialUnits ? "Acceleration [ft/s²]" : "Acceleration [m/s²]"
243+
makePlot(flightlog.imu, el, "IMU - Acceleration", accelerationYLabel, ["Ax", "Ay", "Az"], eventInfo, useImperialUnits)
223244

224245
el = document.createElement("div")
225246
element.append(el)
226247
makePlot(flightlog.imu, el, "IMU - Gyroscope", "Angular Movement [deg/s]", ["Gx", "Gy", "Gz"], eventInfo)
227248

228249
el = document.createElement("div")
229250
element.append(el)
230-
makePlot(flightlog.baro, el, "Temperature", "Temperature [°C]", ["T"], eventInfo)
251+
const temperatureYLabel = useImperialUnits ? "Temperature [°F]" : "Temperature [°C]"
252+
makePlot(flightlog.baro, el, "Temperature", temperatureYLabel, ["T"], eventInfo, useImperialUnits)
231253

232254
el = document.createElement("div")
233255
element.append(el)
234-
makePlot(flightlog.baro, el, "Pressure", "Pressure [hPa]", ["P"], eventInfo)
256+
const pressureYLabel = useImperialUnits ? "Pressure [psi]" : "Pressure [hPa]"
257+
makePlot(flightlog.baro, el, "Pressure", pressureYLabel, ["P"], eventInfo, useImperialUnits)
235258

236259
el = document.createElement("div")
237260
element.append(el)
238-
makePlot(flightlog.filteredDataInfo, el, "Filtered Barometer Altitude", "Altitude [m]", ["filteredAltitudeAGL"], eventInfo)
261+
const filteredAltitudeYLabel = useImperialUnits ? "Altitude [ft]" : "Altitude [m]"
262+
makePlot(flightlog.filteredDataInfo, el, "Filtered Barometer Altitude", filteredAltitudeYLabel, ["filteredAltitudeAGL"], eventInfo, useImperialUnits)
239263

240264
el = document.createElement("div")
241265
element.append(el)

src/modules/settings.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ export const EVENT_SETTINGS = [
4343
];
4444

4545
export const CONFIG_SETTINGS = {
46-
main_altitude: {section: "general", name: "Main Altitude", unit: "m" },
47-
acc_threshold: {section: "general", name: "Liftoff Detection Acceleration", unit: "m/s^2" },
48-
servo1_init_pos: {section: "general", name: "Initial Position Servo 1", unit: "‰" },
49-
servo2_init_pos: {section: "general", name: "Initial Position Servo 2", unit: "‰" },
50-
tele_enable: {section: "telemetry", name: "Enable Telemetry", unit: null},
51-
tele_link_phrase: {section: "telemetry", name: "Link Phrase", unit: null},
52-
tele_power_level: {section: "telemetry", name: "Telemetry Power Level", unit: "dBm" },
53-
tele_adaptive_power: {section: "telemetry", name: "Adaptive Power Level", unit: null},
54-
test_mode: {section: "testing", name: "Enable Testing Mode", unit: null},
55-
tele_test_phrase: {section: "testing", name: "Testing Phrase", unit: null},
46+
main_altitude: { section: "general", name: "Main Altitude", unit: "m" },
47+
acc_threshold: { section: "general", name: "Liftoff Detection Acceleration", unit: "m/s²" },
48+
servo1_init_pos: { section: "general", name: "Initial Position Servo 1", unit: "‰" },
49+
servo2_init_pos: { section: "general", name: "Initial Position Servo 2", unit: "‰" },
50+
tele_enable: { section: "telemetry", name: "Enable Telemetry", unit: null },
51+
tele_link_phrase: { section: "telemetry", name: "Link Phrase", unit: null },
52+
tele_power_level: { section: "telemetry", name: "Telemetry Power Level", unit: "dBm" },
53+
tele_adaptive_power: { section: "telemetry", name: "Adaptive Power Level", unit: null },
54+
test_mode: { section: "testing", name: "Enable Testing Mode", unit: null },
55+
tele_test_phrase: { section: "testing", name: "Testing Phrase", unit: null },
5656
};
5757

5858
export const LOG_ELEMENTS = [

src/store/index.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default new Vuex.Store({
1818
rec_speed: {},
1919
rec_elements: {},
2020
},
21+
useImperialUnits: false,
2122
},
2223
mutations: {
2324
SET_SERIAL_PORTS(state, ports) {
@@ -59,6 +60,9 @@ export default new Vuex.Store({
5960
SET_SUCCESS_MESSAGE(state, value) {
6061
state.successSetMessage = value;
6162
},
63+
SET_USE_IMPERIAL_UNITS(state, value) {
64+
state.useImperialUnits = value;
65+
}
6266
},
6367
actions: {
6468
setSerialPorts({ commit }, ports) {
@@ -74,8 +78,8 @@ export default new Vuex.Store({
7478
if (!payload.key) return;
7579

7680
payload.name = CONFIG_SETTINGS[payload.key]
77-
? CONFIG_SETTINGS[payload.key].name
78-
: null;
81+
? CONFIG_SETTINGS[payload.key].name
82+
: null;
7983

8084
payload.unit = CONFIG_SETTINGS[payload.key]
8185
? CONFIG_SETTINGS[payload.key].unit
@@ -124,6 +128,10 @@ export default new Vuex.Store({
124128
commit("SET_SUCCESS_MESSAGE", value);
125129
setTimeout(() => commit("SET_SUCCESS_MESSAGE", null), 5000);
126130
},
131+
toggleUnitSystem({ commit, state }) {
132+
const newValue = !state.useImperialUnits;
133+
commit("SET_USE_IMPERIAL_UNITS", newValue);
134+
},
127135
},
128136
getters: {
129137
isEventsChanged(state) {
@@ -144,5 +152,8 @@ export default new Vuex.Store({
144152

145153
return changed;
146154
},
155+
useImperialUnits(state) {
156+
return state.useImperialUnits;
157+
}
147158
},
148159
});

0 commit comments

Comments
 (0)