Fix warnings

This commit is contained in:
wjsjwr 2025-07-26 11:55:33 +08:00
parent 78556bbbd7
commit 5716cefced
5 changed files with 176 additions and 22 deletions

View File

@ -17,10 +17,20 @@
"three": "^0.178.0"
},
"devDependencies": {
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/three": "^0.178.1",
"typescript": "~5.8.3",
"vite": "^7.0.4"
}
},
"node_modules/@dimforge/rapier3d-compat": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
"integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.6",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz",
@ -749,6 +759,13 @@
"win32"
]
},
"node_modules/@tweenjs/tween.js": {
"version": "23.1.3",
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
"integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@ -756,6 +773,63 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.1.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
"integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
"dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
"version": "19.1.6",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz",
"integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.0.0"
}
},
"node_modules/@types/stats.js": {
"version": "0.17.4",
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
"integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/three": {
"version": "0.178.1",
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.178.1.tgz",
"integrity": "sha512-WSabew1mgWgRx2RfLfKY+9h4wyg6U94JfLbZEGU245j/WY2kXqU0MUfghS+3AYMV5ET1VlILAgpy77cB6a3Itw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@dimforge/rapier3d-compat": "~0.12.0",
"@tweenjs/tween.js": "~23.1.3",
"@types/stats.js": "*",
"@types/webxr": "*",
"@webgpu/types": "*",
"fflate": "~0.8.2",
"meshoptimizer": "~0.18.1"
}
},
"node_modules/@types/webxr": {
"version": "0.5.22",
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz",
"integrity": "sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==",
"dev": true,
"license": "MIT"
},
"node_modules/@webgpu/types": {
"version": "0.1.64",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.64.tgz",
"integrity": "sha512-84kRIAGV46LJTlJZWxShiOrNL30A+9KokD7RB3dRCIqODFjodS5tCD5yyiZ8kIReGVZSDfA3XkkwyyOIF6K62A==",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -819,6 +893,13 @@
"node": ">=18"
}
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true,
"license": "MIT"
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@ -944,6 +1025,13 @@
}
}
},
"node_modules/fflate": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
"dev": true,
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
@ -1101,6 +1189,13 @@
"node": ">= 0.4"
}
},
"node_modules/meshoptimizer": {
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
"integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
"dev": true,
"license": "MIT"
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",

View File

@ -9,6 +9,9 @@
"preview": "vite preview"
},
"devDependencies": {
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/three": "^0.178.1",
"typescript": "~5.8.3",
"vite": "^7.0.4"
},

View File

@ -1,6 +1,6 @@
import React, { useEffect, useRef } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
interface Point {
x: number;
@ -15,7 +15,7 @@ interface PointCloudProps {
const PointCloud: React.FC<PointCloudProps> = ({ data }) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const rendererRef = useRef<THREE.WebGLRenderer>();
const rendererRef = useRef<THREE.WebGLRenderer | undefined>(undefined);
useEffect(() => {
if (!containerRef.current || data.length === 0) return;
@ -106,12 +106,11 @@ const PointCloud: React.FC<PointCloudProps> = ({ data }) => {
// 图例(颜色条)
const legend = document.createElement("div");
legend.className = "point-cloud-legend";
legend.innerHTML = `
<div style="position:absolute;top:10px;right:10px;background:white;padding:5px;border:1px solid gray;font-size:12px;">
<div style="background:linear-gradient(to top, hsla(180, 100%, 50%, 1.00),hsla(72, 100%, 50%, 1.00), hsla(0, 100%, 50%, 0.99)); width:20px; height:100px;"></div>
<div> High</div>
<div> Low</div>
</div>`;
<div class="legend-gradient"></div>
<div> High</div>
<div> Low</div>`;
containerRef.current.appendChild(legend);
// 清理
@ -123,7 +122,7 @@ const PointCloud: React.FC<PointCloudProps> = ({ data }) => {
};
}, [data]);
return <div ref={containerRef} style={{ width: "100%", height: "100%", position: "relative" }} />;
return <div ref={containerRef} className="point-cloud-container" />;
};
export default PointCloud;

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import PointCloud from "../components/PointCloud";
import "../style.css";
const GeneView: React.FC = () => {
const [gene, setGene] = useState("");
@ -53,11 +54,11 @@ const GeneView: React.FC = () => {
};
return (
<div style={{ padding: "1rem" }}>
<div className="gene-view-container">
<h2>Gene Expression Viewer</h2>
{/* 阶段选择 */}
<div style={{ marginBottom: "10px" }}>
<div className="stage-selector">
<label>
Stage:&nbsp;
<select
@ -77,11 +78,14 @@ const GeneView: React.FC = () => {
</div>
{/* 基因选择 + 按钮 */}
<div style={{ marginBottom: "1rem" }}>
<div className="gene-selector">
<label htmlFor="gene-select" className="gene-label">Gene:</label>
<select
id="gene-select"
aria-label="选择基因"
value={gene}
onChange={(e) => setGene(e.target.value)}
style={{ marginRight: "1rem" }}
className="gene-select"
>
<option value="">-- Select a gene --</option>
{availableGenes.map((g) => (
@ -96,21 +100,14 @@ const GeneView: React.FC = () => {
</div>
{/* 错误提示 */}
{error && <p style={{ color: "red" }}>{error}</p>}
{error && <p className="error-message">{error}</p>}
{/* 可视化区域 */}
<div
style={{
width: "100%",
height: "600px",
border: "1px solid #ccc",
position: "relative",
}}
>
<div className="visualization-container">
{data.length > 0 ? (
<PointCloud data={data} />
) : (
<p style={{ textAlign: "center", paddingTop: "2rem" }}>
<p className="no-data-message">
No data to display.
</p>
)}

View File

@ -82,6 +82,66 @@ button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
/* GeneView component styles */
.gene-view-container {
padding: 1rem;
}
.stage-selector {
margin-bottom: 10px;
}
.gene-selector {
margin-bottom: 1rem;
}
.gene-label {
margin-right: 0.5rem;
}
.gene-select {
margin-right: 1rem;
}
.error-message {
color: red;
}
.visualization-container {
width: 100%;
height: 600px;
border: 1px solid #ccc;
position: relative;
}
.no-data-message {
text-align: center;
padding-top: 2rem;
}
/* PointCloud component styles */
.point-cloud-container {
width: 100%;
height: 100%;
position: relative;
}
.point-cloud-legend {
position: absolute;
top: 10px;
right: 10px;
background: white;
padding: 5px;
border: 1px solid gray;
font-size: 12px;
}
.legend-gradient {
background: linear-gradient(to top, hsla(180, 100%, 50%, 1.00), hsla(72, 100%, 50%, 1.00), hsla(0, 100%, 50%, 0.99));
width: 20px;
height: 100px;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;