mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-30 02:31:40 +00:00
TypeCheck Frontend (#2394)
We recently had an error that would've been caught by type checking in the frontend (see #2393). This PR implements type checking so that future errors will be caught. Additionally, this PR contains miscellaneous frontend cleanup that's tangentially related to type-checking.
This commit is contained in:
@@ -3,7 +3,7 @@ import type { PhotonTarget } from "@/types/PhotonTrackingTypes";
|
||||
// @ts-expect-error Intellisense says these conflict with the dynamic imports below
|
||||
import type { Mesh, Object3D, PerspectiveCamera, Scene, WebGLRenderer } from "three";
|
||||
// @ts-expect-error Intellisense says these conflict with the dynamic imports below
|
||||
import type { TrackballControls } from "three/examples/jsm/controls/TrackballControls";
|
||||
import type { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js";
|
||||
import { onBeforeUnmount, onMounted, watchEffect } from "vue";
|
||||
const {
|
||||
ArrowHelper,
|
||||
@@ -20,7 +20,7 @@ const {
|
||||
Scene,
|
||||
WebGLRenderer
|
||||
} = await import("three");
|
||||
const { TrackballControls } = await import("three/examples/jsm/controls/TrackballControls");
|
||||
const { TrackballControls } = await import("three/examples/jsm/controls/TrackballControls.js");
|
||||
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { createPerspectiveCamera } from "@/lib/ThreeUtils";
|
||||
@@ -213,14 +213,14 @@ onMounted(async () => {
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
drawTargets(props.targets);
|
||||
await drawTargets(props.targets);
|
||||
animate();
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("resize", onWindowResize);
|
||||
});
|
||||
watchEffect(() => {
|
||||
drawTargets(props.targets);
|
||||
void drawTargets(props.targets);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, ref, watch, watchEffect, type Ref } from "vue";
|
||||
import type {
|
||||
Scene as SceneType,
|
||||
PerspectiveCamera as PerspectiveCameraType,
|
||||
WebGLRenderer as WebGLRendererType,
|
||||
Group as GroupType,
|
||||
Object3D
|
||||
} from "three";
|
||||
import type { TrackballControls as TrackballControlsType } from "three/examples/jsm/controls/TrackballControls.js";
|
||||
const {
|
||||
AmbientLight,
|
||||
AxesHelper,
|
||||
@@ -16,7 +24,7 @@ const {
|
||||
SphereGeometry,
|
||||
WebGLRenderer
|
||||
} = await import("three");
|
||||
const { TrackballControls } = await import("three/examples/jsm/controls/TrackballControls");
|
||||
const { TrackballControls } = await import("three/examples/jsm/controls/TrackballControls.js");
|
||||
import type { BoardObservation, CameraCalibrationResult } from "@/types/SettingTypes";
|
||||
import axios from "axios";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
@@ -31,12 +39,12 @@ const props = defineProps<{
|
||||
title: string;
|
||||
}>();
|
||||
|
||||
let scene: Scene | undefined;
|
||||
let camera: PerspectiveCamera | undefined;
|
||||
let renderer: WebGLRenderer | undefined;
|
||||
let controls: TrackballControls | undefined;
|
||||
let scene: SceneType | undefined;
|
||||
let camera: PerspectiveCameraType | undefined;
|
||||
let renderer: WebGLRendererType | undefined;
|
||||
let controls: TrackballControlsType | undefined;
|
||||
|
||||
const createChessboard = (obs: BoardObservation, cal: CameraCalibrationResult): Group => {
|
||||
const createChessboard = (obs: BoardObservation, cal: CameraCalibrationResult): GroupType => {
|
||||
const group = new Group();
|
||||
|
||||
if (obs.locationInImageSpace.length === 0) return group;
|
||||
@@ -194,9 +202,6 @@ const resetCamThirdPerson = () => {
|
||||
let animationFrameId: number | null = null;
|
||||
|
||||
onMounted(async () => {
|
||||
// Grab data first off
|
||||
fetchCalibrationData();
|
||||
|
||||
scene = new Scene();
|
||||
camera = new PerspectiveCamera(75, 800 / 800, 0.1, 1000);
|
||||
|
||||
@@ -256,6 +261,10 @@ onMounted(async () => {
|
||||
|
||||
controls.update();
|
||||
|
||||
// Fetch calibration only after the scene is ready so the initial draw
|
||||
// can happen immediately when the data arrives.
|
||||
await fetchCalibrationData();
|
||||
|
||||
const animate = () => {
|
||||
if (!scene || !camera || !renderer || !controls) {
|
||||
return;
|
||||
@@ -318,7 +327,7 @@ if (import.meta.hot) {
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
drawCalibration(calibrationData.value);
|
||||
void drawCalibration(calibrationData.value);
|
||||
});
|
||||
|
||||
watch(
|
||||
@@ -328,9 +337,9 @@ watch(
|
||||
props.resolution.height,
|
||||
useCameraSettingsStore().getCalibrationCoeffs(props.resolution)
|
||||
],
|
||||
() => {
|
||||
async () => {
|
||||
console.log("Camera or resolution changed, refetching calibration");
|
||||
fetchCalibrationData();
|
||||
await fetchCalibrationData();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, ref, onBeforeUnmount } from "vue";
|
||||
import { computed, inject, onBeforeUnmount, useTemplateRef } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import type { StyleValue } from "vue";
|
||||
@@ -13,6 +13,7 @@ const props = defineProps<{
|
||||
cameraSettings: UiCameraConfiguration;
|
||||
}>();
|
||||
|
||||
const backendHostname = inject<string>("backendHostname");
|
||||
const emptyStreamSrc = "//:0";
|
||||
const streamSrc = computed<string>(() => {
|
||||
const port = props.cameraSettings.stream[props.streamType === "Raw" ? "inputPort" : "outputPort"];
|
||||
@@ -21,7 +22,7 @@ const streamSrc = computed<string>(() => {
|
||||
return emptyStreamSrc;
|
||||
}
|
||||
|
||||
return `http://${inject("backendHostname")}:${port}/stream.mjpg`;
|
||||
return `http://${backendHostname}:${port}/stream.mjpg`;
|
||||
});
|
||||
const streamDesc = computed<string>(() => `${props.streamType} Stream View`);
|
||||
const streamStyle = computed<StyleValue>(() => {
|
||||
@@ -67,26 +68,26 @@ const handleCaptureClick = () => {
|
||||
const handlePopoutClick = () => {
|
||||
window.open(streamSrc.value);
|
||||
};
|
||||
const handleFullscreenRequest = () => {
|
||||
const handleFullscreenRequest = async () => {
|
||||
const stream = document.getElementById(props.id);
|
||||
if (!stream) return;
|
||||
stream.requestFullscreen();
|
||||
await stream.requestFullscreen();
|
||||
};
|
||||
|
||||
const mjpgStream: any = ref(null);
|
||||
const mjpgStream = useTemplateRef("mjpgStream");
|
||||
|
||||
const handleStreamError = () => {
|
||||
if (streamSrc.value && streamSrc.value !== emptyStreamSrc) {
|
||||
console.error("Error loading stream:", streamSrc.value, " Trying again.");
|
||||
setTimeout(() => {
|
||||
mjpgStream.value.src = streamSrc.value;
|
||||
mjpgStream.value!.src = streamSrc.value;
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (!mjpgStream.value) return;
|
||||
mjpgStream.value["src"] = emptyStreamSrc;
|
||||
mjpgStream.value.src = emptyStreamSrc;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, ref, watch } from "vue";
|
||||
import { computed, inject, ref, useTemplateRef, watch } from "vue";
|
||||
import { LogLevel, type LogMessage } from "@/types/SettingTypes";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import LogEntry from "@/components/app/photon-log-entry.vue";
|
||||
@@ -10,10 +10,10 @@ const backendHost = inject<string>("backendHost");
|
||||
const searchQuery = ref("");
|
||||
const timeInput = ref<string>();
|
||||
const autoScroll = ref(true);
|
||||
const logList = ref();
|
||||
const logList = useTemplateRef<InstanceType<typeof VirtualList>>("logList"); // this needs to be typed in the definition since vue has trouble inferring it
|
||||
const logKeeps = ref(40);
|
||||
const exportLogFile = ref();
|
||||
const selectedLogLevels = ref({
|
||||
const exportLogFile = useTemplateRef("exportLogFile");
|
||||
const selectedLogLevels = ref<Record<number, boolean>>({
|
||||
[LogLevel.ERROR]: true,
|
||||
[LogLevel.WARN]: true,
|
||||
[LogLevel.INFO]: true,
|
||||
@@ -48,7 +48,7 @@ watch(logs, () => {
|
||||
);
|
||||
autoScroll.value = bottomOffset < 50;
|
||||
|
||||
if (autoScroll.value) logList.value.scrollToBottom();
|
||||
if (autoScroll.value) logList.value?.scrollToBottom();
|
||||
});
|
||||
|
||||
const getLogLevelFromIndex = (index: number): string => {
|
||||
@@ -56,7 +56,7 @@ const getLogLevelFromIndex = (index: number): string => {
|
||||
};
|
||||
|
||||
const handleLogExport = () => {
|
||||
exportLogFile.value.click();
|
||||
exportLogFile.value?.click();
|
||||
};
|
||||
|
||||
const handleLogClear = () => {
|
||||
|
||||
Reference in New Issue
Block a user