feat: 星图响应式布局适配 - ResizeObserver + 窄屏55/45上下分/宽屏左右分 (@ohos.display)

This commit is contained in:
root
2026-04-30 10:29:51 +08:00
parent d594099f02
commit c060a59710
2 changed files with 127 additions and 20 deletions

View File

@ -1,38 +1,82 @@
import { GraphDatabase } from '../model/GraphDatabase'; import { GraphDatabase } from '../model/GraphDatabase';
import { GraphPage } from './GraphPage'; import { GraphPage } from './GraphPage';
import { ChatPage } from './ChatPage'; import { ChatPage } from './ChatPage';
import display from '@ohos.display';
@Component @Component
export struct MainPage { export struct MainPage {
@Prop db: GraphDatabase; @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() { build() {
GridRow({ columns: { sm: 1, md: 2, lg: 2 }, gutter: { x: 8, y: 8 } }) { if (this.isWide) {
GridCol({ span: { sm: 1, md: 1, lg: 1 } }) { // ======== 宽屏模式(>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() { Stack() {
GraphPage({ db: this.db }) GraphPage({ db: this.db })
} }
.backgroundColor('rgba(255,255,255,0.05)') .height('55%')
.borderRadius(12)
.backgroundBlurStyle(BlurStyle.Thin)
.width('100%') .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() { Stack() {
ChatPage({ db: this.db }) ChatPage({ db: this.db })
} }
.backgroundColor('rgba(255,255,255,0.05)') .height('45%')
.borderRadius(12)
.backgroundBlurStyle(BlurStyle.Thin)
.width('100%') .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)
} }
} }

View File

@ -121,7 +121,8 @@
mouse = new THREE.Vector2(); mouse = new THREE.Vector2();
createStarField(); createStarField();
createNebula(); createNebula();
window.addEventListener('resize', onWindowResize); // 使用 ResizeObserver 监听容器尺寸变化(比 window.resize 更准确)
initResizeObserver();
renderer.domElement.addEventListener('mousemove', onMouseMove); renderer.domElement.addEventListener('mousemove', onMouseMove);
renderer.domElement.addEventListener('click', onMouseClick); renderer.domElement.addEventListener('click', onMouseClick);
window.addEventListener('message', (event) => { window.addEventListener('message', (event) => {
@ -742,10 +743,72 @@
} }
} }
function onWindowResize() { // ========= ResizeObserver 响应式适配 =========
camera.aspect = window.innerWidth / window.innerHeight; 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(); 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() { function animate() {