From c060a59710ce195e95a5f8f9a00b2074f57c8cf2 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 30 Apr 2026 10:29:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=98=9F=E5=9B=BE=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=BC=8F=E5=B8=83=E5=B1=80=E9=80=82=E9=85=8D=20-=20ResizeObser?= =?UTF-8?q?ver=20+=20=E7=AA=84=E5=B1=8F55/45=E4=B8=8A=E4=B8=8B=E5=88=86/?= =?UTF-8?q?=E5=AE=BD=E5=B1=8F=E5=B7=A6=E5=8F=B3=E5=88=86=20(@ohos.display)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/ets/pages/MainPage.ets | 76 ++++++++++++++++----- entry/src/main/resources/rawfile/graph.html | 71 +++++++++++++++++-- 2 files changed, 127 insertions(+), 20 deletions(-) diff --git a/entry/src/main/ets/pages/MainPage.ets b/entry/src/main/ets/pages/MainPage.ets index fc48dc7..741e878 100644 --- a/entry/src/main/ets/pages/MainPage.ets +++ b/entry/src/main/ets/pages/MainPage.ets @@ -1,38 +1,82 @@ import { GraphDatabase } from '../model/GraphDatabase'; import { GraphPage } from './GraphPage'; import { ChatPage } from './ChatPage'; +import display from '@ohos.display'; @Component export struct MainPage { @Prop db: GraphDatabase; + @State isWide: boolean = false; + + aboutToAppear() { + this.updateBreakpoint(); + try { + display.on('change', () => { + this.updateBreakpoint(); + }); + } catch (e) { + console.error('display.on error: ' + JSON.stringify(e)); + } + } + + private updateBreakpoint(): void { + try { + const defaultWindow = display.getDefaultDisplaySync(); + this.isWide = defaultWindow.width > 520; + } catch (e) { + console.error('updateBreakpoint error: ' + JSON.stringify(e)); + } + } build() { - GridRow({ columns: { sm: 1, md: 2, lg: 2 }, gutter: { x: 8, y: 8 } }) { - GridCol({ span: { sm: 1, md: 1, lg: 1 } }) { + if (this.isWide) { + // ======== 宽屏模式(>520px):左侧星图 + 右侧聊天 ======== + Row() { + GraphPage({ db: this.db }) + .layoutWeight(1) + .height('100%') + .clip(true) + .borderRadius(12) + .margin({ left: 4, right: 2 }) + + ChatPage({ db: this.db }) + .width(380) + .height('100%') + .clip(true) + .borderRadius(12) + .margin({ left: 2, right: 4 }) + } + .width('100%') + .height('100%') + .padding(4) + .backgroundColor('#1A1B2E') + .backgroundBlurStyle(BlurStyle.Regular) + } else { + // ======== 窄屏模式(≤520px):上方星图(55%) + 下方聊天(45%) ======== + Column() { Stack() { GraphPage({ db: this.db }) } - .backgroundColor('rgba(255,255,255,0.05)') - .borderRadius(12) - .backgroundBlurStyle(BlurStyle.Thin) + .height('55%') .width('100%') - .height('100%') - } + .clip(true) + .borderRadius(12) + .margin({ top: 2, left: 4, right: 4, bottom: 2 }) - GridCol({ span: { sm: 1, md: 1, lg: 1 } }) { Stack() { ChatPage({ db: this.db }) } - .backgroundColor('rgba(255,255,255,0.05)') - .borderRadius(12) - .backgroundBlurStyle(BlurStyle.Thin) + .height('45%') .width('100%') - .height('100%') + .clip(true) + .borderRadius(12) + .margin({ top: 2, left: 4, right: 4, bottom: 2 }) } + .width('100%') + .height('100%') + .padding(2) + .backgroundColor('#1A1B2E') + .backgroundBlurStyle(BlurStyle.Regular) } - .width('100%') - .height('100%') - .backgroundColor('#1A1B2E') - .backgroundBlurStyle(BlurStyle.Regular) } } diff --git a/entry/src/main/resources/rawfile/graph.html b/entry/src/main/resources/rawfile/graph.html index 446758c..2a26322 100644 --- a/entry/src/main/resources/rawfile/graph.html +++ b/entry/src/main/resources/rawfile/graph.html @@ -121,7 +121,8 @@ mouse = new THREE.Vector2(); createStarField(); createNebula(); - window.addEventListener('resize', onWindowResize); + // 使用 ResizeObserver 监听容器尺寸变化(比 window.resize 更准确) + initResizeObserver(); renderer.domElement.addEventListener('mousemove', onMouseMove); renderer.domElement.addEventListener('click', onMouseClick); window.addEventListener('message', (event) => { @@ -742,10 +743,72 @@ } } - function onWindowResize() { - camera.aspect = window.innerWidth / window.innerHeight; + // ========= ResizeObserver 响应式适配 ========= + let containerObserver = null; + function initResizeObserver() { + const container = document.getElementById('canvas-container'); + if (!container) return; + containerObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const { width, height } = entry.contentRect; + if (width > 0 && height > 0) { + onContainerResize(width, height); + } + } + }); + containerObserver.observe(container); + } + + function onContainerResize(width, height) { + if (!camera || !renderer) return; + const aspect = width / height; + camera.aspect = aspect; camera.updateProjectionMatrix(); - renderer.setSize(window.innerWidth, window.innerHeight); + renderer.setSize(width, height); + + // 窄屏(<500px)时自动调整UI元素尺寸和位置 + const isNarrow = width < 500; + const stats = document.getElementById('stats'); + const nodeInfo = document.getElementById('node-info'); + const searchBox = document.getElementById('search-box'); + const typeFilter = document.getElementById('type-filter'); + const searchInput = document.getElementById('search-input'); + + if (isNarrow) { + if (stats) { + stats.style.fontSize = '11px'; + stats.style.padding = '8px 12px'; + stats.style.top = '6px'; + stats.style.left = '6px'; + } + if (nodeInfo) { + nodeInfo.style.fontSize = '11px'; + nodeInfo.style.padding = '8px 12px'; + nodeInfo.style.maxWidth = '180px'; + nodeInfo.style.top = '6px'; + nodeInfo.style.right = '6px'; + } + if (searchBox) { searchBox.style.top = '70px'; searchBox.style.left = '6px'; } + if (searchInput) { searchInput.style.width = '140px'; searchInput.style.fontSize = '12px'; } + if (typeFilter) { typeFilter.style.top = '108px'; typeFilter.style.left = '6px'; } + } else { + if (stats) { + stats.style.fontSize = '14px'; + stats.style.padding = '15px 20px'; + stats.style.top = '20px'; + stats.style.left = '20px'; + } + if (nodeInfo) { + nodeInfo.style.fontSize = '14px'; + nodeInfo.style.padding = '15px 20px'; + nodeInfo.style.maxWidth = '300px'; + nodeInfo.style.top = '20px'; + nodeInfo.style.right = '20px'; + } + if (searchBox) { searchBox.style.top = '80px'; searchBox.style.left = '20px'; } + if (searchInput) { searchInput.style.width = '200px'; searchInput.style.fontSize = '14px'; } + if (typeFilter) { typeFilter.style.top = '120px'; typeFilter.style.left = '20px'; } + } } function animate() {