refactor: 优化模型尺寸的处理逻辑 (#552)

This commit is contained in:
ayangweb
2025-07-11 19:29:49 +08:00
committed by GitHub
parent 496852630b
commit 7d541a486e
4 changed files with 38 additions and 40 deletions

View File

@@ -1,37 +1,34 @@
import { convertFileSrc } from '@tauri-apps/api/core'
import { LogicalSize, PhysicalSize } from '@tauri-apps/api/dpi'
import { resolveResource } from '@tauri-apps/api/path'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { message } from 'ant-design-vue'
import { isNil, round } from 'es-toolkit'
import { computed, watch } from 'vue'
import { ref, watch } from 'vue'
import live2d from '../utils/live2d'
import { getCursorMonitor } from '../utils/monitor'
import { useCatStore } from '@/stores/cat'
import { useModelStore } from '@/stores/model'
import { getImageSize } from '@/utils/dom'
import { join } from '@/utils/path'
const appWindow = getCurrentWebviewWindow()
interface ModelSize {
width: number
height: number
}
export function useModel() {
const modelStore = useModelStore()
const catStore = useCatStore()
const backgroundImage = computed(() => {
if (!modelStore.currentModel) return
return convertFileSrc(join(modelStore.currentModel.path, 'resources', 'background.png'))
})
const modelSize = ref<ModelSize>()
watch(() => modelStore.currentModel, handleLoad, { deep: true, immediate: true })
watch([() => catStore.scale, backgroundImage], async () => {
if (!backgroundImage.value) return
watch([() => catStore.scale, modelSize], async () => {
if (!modelSize.value) return
const { width, height } = await getImageSize(backgroundImage.value)
const { width, height } = modelSize.value
appWindow.setSize(
new PhysicalSize({
@@ -49,11 +46,13 @@ export function useModel() {
await resolveResource(path)
const data = await live2d.load(path)
const { width, height, ...rest } = await live2d.load(path)
modelSize.value = { width, height }
handleResize()
Object.assign(modelStore, data)
Object.assign(modelStore, rest)
} catch (error) {
message.error(String(error))
}
@@ -64,11 +63,11 @@ export function useModel() {
}
async function handleResize() {
if (!backgroundImage.value) return
if (!modelSize.value) return
live2d.fitModel()
const { width, height } = await getImageSize(backgroundImage.value)
const { width, height } = modelSize.value
if (round(innerWidth / innerHeight, 1) !== round(width / height, 1)) {
await appWindow.setSize(
@@ -134,7 +133,6 @@ export function useModel() {
}
return {
backgroundImage,
handleLoad,
handleDestroy,
handleResize,

View File

@@ -2,6 +2,7 @@
import { convertFileSrc, invoke } from '@tauri-apps/api/core'
import { Menu } from '@tauri-apps/api/menu'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { exists } from '@tauri-apps/plugin-fs'
import { useDebounceFn, useEventListener } from '@vueuse/core'
import { onMounted, onUnmounted, ref, watch } from 'vue'
@@ -16,11 +17,12 @@ import { join } from '@/utils/path'
const appWindow = getCurrentWebviewWindow()
const { pressedMouses, mousePosition, pressedLeftKeys, pressedRightKeys } = useDevice()
const { backgroundImage, handleDestroy, handleResize, handleMouseDown, handleMouseMove, handleKeyDown } = useModel()
const { handleDestroy, handleResize, handleMouseDown, handleMouseMove, handleKeyDown } = useModel()
const catStore = useCatStore()
const { getSharedMenu } = useSharedMenu()
const modelStore = useModelStore()
const resizing = ref(false)
const backgroundImagePath = ref<string>()
onMounted(() => {
invoke(INVOKE_KEY.START_DEVICE_LISTENING)
@@ -62,6 +64,16 @@ watch(() => catStore.penetrable, (value) => {
watch(() => catStore.alwaysOnTop, setAlwaysOnTop, { immediate: true })
watch(() => modelStore.currentModel, async (model) => {
if (!model) return
const path = join(model.path, 'resources', 'background.png')
const existed = await exists(path)
backgroundImagePath.value = existed ? convertFileSrc(path) : void 0
}, { deep: true, immediate: true })
function handleWindowDrag() {
appWindow.startDragging()
}
@@ -76,7 +88,7 @@ async function handleContextmenu(event: MouseEvent) {
menu.popup()
}
function resolveImagePath(key: string, side: 'left' | 'right' = 'left') {
function resolveKeyImagePath(key: string, side: 'left' | 'right' = 'left') {
return convertFileSrc(join(modelStore.currentModel!.path, 'resources', `${side}-keys`, `${key}.png`))
}
</script>
@@ -89,22 +101,23 @@ function resolveImagePath(key: string, side: 'left' | 'right' = 'left') {
@contextmenu="handleContextmenu"
@mousedown="handleWindowDrag"
>
<img :src="backgroundImage">
<img
v-if="backgroundImagePath"
:src="backgroundImagePath"
>
<canvas id="live2dCanvas" />
<img
v-for="key in pressedLeftKeys"
:key="key"
class="object-contain"
:src="resolveImagePath(key)"
:src="resolveKeyImagePath(key)"
>
<img
v-for="key in pressedRightKeys"
:key="key"
class="object-contain"
:src="resolveImagePath(key, 'right')"
:src="resolveKeyImagePath(key, 'right')"
>
<div

View File

@@ -1,15 +0,0 @@
export function getImageSize(src: string) {
return new Promise<{ width: number, height: number }>((resolve, reject) => {
const img = new Image()
img.src = src
img.onload = () => {
const { naturalWidth, naturalHeight } = img
resolve({ width: naturalWidth, height: naturalHeight })
}
img.onerror = reject
})
}

View File

@@ -67,6 +67,8 @@ class Live2d {
const { motions, expressions } = modelSettings
return {
width,
height,
motions,
expressions,
}