Skip to content

Commit f7684d2

Browse files
committed
✨ 实现节点搜索并一项一项切换视角
1 parent 565f52f commit f7684d2

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

src/core/controller/Controller.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ export namespace Controller {
178178
StageManager.nodes.filter((node) => node.isSelected),
179179
);
180180
}
181+
// 检测按下 ctrl + F 搜索
182+
if (event.ctrlKey && key === "f") {
183+
184+
}
181185
}
182186

183187
function keyup(event: KeyboardEvent) {

src/core/stage/Stage.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ export namespace Stage {
7070
*/
7171
export let keyOnlyVirtualNewLocation = Vector.getZero();
7272

73+
/**
74+
* 搜索结果
75+
*/
76+
export let searchResultNodes: Node[] = [];
77+
/**
78+
* 搜索结果的索引
79+
*/
80+
export let currentSearchResultIndex = 0;
7381
/**
7482
* 逻辑总入口
7583
*/

src/pages/index.tsx

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { StageManager } from "../core/stage/stageManager/StageManager";
88
import React from "react";
99
import Toolbar from "./_toolbar";
1010
import { Settings } from "../core/Settings";
11-
import { invoke } from "@tauri-apps/api/core";
11+
import { cn } from "../utils/cn";
12+
import { Camera } from "../core/stage/Camera";
1213

1314
export default function Home() {
1415
const canvasRef: React.RefObject<HTMLCanvasElement> = useRef(null);
@@ -17,6 +18,24 @@ export default function Home() {
1718
const dialog = useDialog();
1819
const [cursorName, setCursorName] = React.useState("default");
1920

21+
const [isSearchingShow, setIsSearchingShow] = React.useState(false);
22+
23+
const [currentSearchResultIndex, setCurrentSearchResultIndex] =
24+
React.useState(0);
25+
26+
useEffect(() => {
27+
if (Stage.searchResultNodes.length == 0) {
28+
setCurrentSearchResultIndex(-1);
29+
} else {
30+
setCurrentSearchResultIndex(Stage.currentSearchResultIndex);
31+
}
32+
}, [Stage.currentSearchResultIndex]);
33+
34+
const [searchResultCount, setSearchResultCount] = React.useState(0);
35+
useEffect(() => {
36+
setSearchResultCount(Stage.searchResultNodes.length);
37+
}, [Stage.searchResultNodes]);
38+
2039
useEffect(() => {
2140
const handleResize = () => {
2241
if (canvasElement) {
@@ -29,6 +48,41 @@ export default function Home() {
2948
const handleBlur = () => {
3049
focus = false;
3150
};
51+
const handleKeyDown = (event: KeyboardEvent) => {
52+
// event.preventDefault();
53+
if (Controller.pressingKeySet.has("control") && event.key === "f") {
54+
Controller.pressingKeySet.clear();
55+
// setIsSearching(true);
56+
const searchString = prompt("请输入要搜索的节点名称");
57+
if (searchString) {
58+
// 开始搜索
59+
Stage.searchResultNodes = [];
60+
for (const node of StageManager.nodes) {
61+
if (node.text.includes(searchString)) {
62+
Stage.searchResultNodes.push(node);
63+
}
64+
}
65+
Stage.currentSearchResultIndex = 0;
66+
if (Stage.searchResultNodes.length > 0) {
67+
setIsSearchingShow(true);
68+
setCurrentSearchResultIndex(0);
69+
// 选择第一个搜索结果节点
70+
const currentNode =
71+
Stage.searchResultNodes[Stage.currentSearchResultIndex];
72+
currentNode.isSelected = true;
73+
// 摄像机对准现在的节点
74+
Camera.location = currentNode.rectangle.center.clone();
75+
} else {
76+
dialog.show({
77+
title: "提示",
78+
type: "info",
79+
content: "没有找到匹配的节点",
80+
});
81+
}
82+
}
83+
}
84+
// setSearchString(searchString + event.key)
85+
};
3286

3387
const canvasElement = canvasRef.current;
3488
let focus = true;
@@ -49,6 +103,7 @@ export default function Home() {
49103
window.addEventListener("resize", handleResize);
50104
window.addEventListener("focus", handleFocus);
51105
window.addEventListener("blur", handleBlur);
106+
window.addEventListener("keydown", handleKeyDown);
52107

53108
Settings.get("windowBackgroundAlpha").then((value) => {
54109
Renderer.backgroundAlpha = value;
@@ -86,11 +141,70 @@ export default function Home() {
86141
return (
87142
<>
88143
<Toolbar />
144+
{isSearchingShow && (
145+
<div
146+
className={cn(
147+
"fixed right-32 top-32 z-10 flex transform items-center rounded p-4 ring",
148+
isSearchingShow,
149+
)}
150+
>
151+
<span>
152+
{currentSearchResultIndex + 1}/{searchResultCount}
153+
</span>
154+
<button
155+
className="m-2 rounded-md bg-gray-500 text-white"
156+
onClick={() => {
157+
if (Stage.currentSearchResultIndex > 0) {
158+
Stage.currentSearchResultIndex--;
159+
}
160+
// 取消选择所有节点
161+
for (const node of StageManager.nodes) {
162+
node.isSelected = false;
163+
}
164+
// 选择当前搜索结果节点
165+
const currentNode =
166+
Stage.searchResultNodes[Stage.currentSearchResultIndex];
167+
currentNode.isSelected = true;
168+
// 摄像机对准现在的节点
169+
Camera.location = currentNode.rectangle.center.clone();
170+
}}
171+
>
172+
Previous
173+
</button>
174+
<button
175+
className="m-2 rounded-md bg-gray-500 text-white"
176+
onClick={() => {
177+
if (Stage.currentSearchResultIndex < searchResultCount - 1) {
178+
Stage.currentSearchResultIndex++;
179+
}
180+
// 取消选择所有节点
181+
for (const node of StageManager.nodes) {
182+
node.isSelected = false;
183+
}
184+
// 选择当前搜索结果节点
185+
const currentNode =
186+
Stage.searchResultNodes[Stage.currentSearchResultIndex];
187+
currentNode.isSelected = true;
188+
// 摄像机对准现在的节点
189+
Camera.location = currentNode.rectangle.center.clone();
190+
}}
191+
>
192+
Next
193+
</button>
194+
<button
195+
className="m-2 rounded-md bg-gray-500 text-white"
196+
onClick={() => {
197+
setIsSearchingShow(false);
198+
}}
199+
>
200+
关闭
201+
</button>
202+
</div>
203+
)}
89204
<span
90205
className="fixed bottom-0 left-0 cursor-pointer ring"
91206
onClick={() => {
92207
window.location.reload();
93-
invoke<string>("save_json_by_path");
94208
}}
95209
>
96210
FPS={fps.toFixed()}

0 commit comments

Comments
 (0)