refactor: dynamic calculation of background image size (#375)

This commit is contained in:
ayangweb
2025-05-25 22:28:41 +08:00
committed by GitHub
parent 907c598cba
commit 10a58db80a
4 changed files with 38 additions and 26 deletions

View File

@@ -1,16 +1,18 @@
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 { round } from 'es-toolkit'
import { watch } from 'vue'
import { computed, watch } from 'vue'
import live2d from '../utils/live2d'
import { getCursorMonitor } from '../utils/monitor'
import { DEFAULT_MODEL_HEIGHT, DEFAULT_MODEL_WIDTH } from '@/constants'
import { useCatStore } from '@/stores/cat'
import { useModelStore } from '@/stores/model'
import { getImageSize } from '@/utils/dom'
import { join } from '@/utils/path'
const appWindow = getCurrentWebviewWindow()
@@ -18,22 +20,26 @@ export function useModel() {
const modelStore = useModelStore()
const catStore = useCatStore()
const backgroundImage = computed(() => {
return convertFileSrc(join(modelStore.currentModel!.path, 'resources', 'background.png'))
})
watch(() => modelStore.currentModel, handleLoad, { deep: true, immediate: true })
watch(() => catStore.scale, async () => {
const { width, height } = await getImageSize(backgroundImage.value)
appWindow.setSize(
new PhysicalSize({
width: round(DEFAULT_MODEL_WIDTH * (catStore.scale / 100)),
height: round(DEFAULT_MODEL_HEIGHT * (catStore.scale / 100)),
width: round(width * (catStore.scale / 100)),
height: round(height * (catStore.scale / 100)),
}),
)
}, { immediate: true })
async function handleLoad() {
try {
if (!modelStore.currentModel) return
const { path } = modelStore.currentModel
const { path } = modelStore.currentModel!
await resolveResource(path)
@@ -56,20 +62,22 @@ export function useModel() {
const { innerWidth, innerHeight } = window
live2d.model?.scale.set(innerWidth / DEFAULT_MODEL_WIDTH)
const { width, height } = await getImageSize(backgroundImage.value)
if (round(innerWidth / innerHeight, 1) !== round(DEFAULT_MODEL_WIDTH / DEFAULT_MODEL_HEIGHT, 1)) {
live2d.model?.scale.set(innerWidth / width)
if (round(innerWidth / innerHeight, 1) !== round(width / height, 1)) {
await appWindow.setSize(
new LogicalSize({
width: innerWidth,
height: Math.ceil(innerWidth * (DEFAULT_MODEL_HEIGHT / DEFAULT_MODEL_WIDTH)),
height: Math.ceil(innerWidth * (height / width)),
}),
)
}
const size = await appWindow.size()
catStore.scale = round((size.width / DEFAULT_MODEL_WIDTH) * 100)
catStore.scale = round((size.width / width) * 100)
}
function handleKeyDown(side: 'left' | 'right', pressed: boolean) {
@@ -109,6 +117,7 @@ export function useModel() {
}
return {
backgroundImage,
handleLoad,
handleDestroy,
handleResize,

View File

@@ -7,10 +7,6 @@ export const LISTEN_KEY = {
UPDATE_APP: 'update-app',
}
export const DEFAULT_MODEL_WIDTH = 612
export const DEFAULT_MODEL_HEIGHT = 354
export const INVOKE_KEY = {
COPY_DIR: 'copy_dir',
}

View File

@@ -3,7 +3,7 @@ import { convertFileSrc } from '@tauri-apps/api/core'
import { Menu } from '@tauri-apps/api/menu'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { useDebounceFn, useEventListener } from '@vueuse/core'
import { computed, onUnmounted, ref, watch } from 'vue'
import { onUnmounted, ref, watch } from 'vue'
import { useDevice } from '@/composables/useDevice'
import { useModel } from '@/composables/useModel'
@@ -14,7 +14,7 @@ import { join } from '@/utils/path'
const appWindow = getCurrentWebviewWindow()
const { pressedMouses, mousePosition, pressedLeftKeys, pressedRightKeys } = useDevice()
const { handleDestroy, handleResize, handleMouseDown, handleMouseMove, handleKeyDown } = useModel()
const { backgroundImage, handleDestroy, handleResize, handleMouseDown, handleMouseMove, handleKeyDown } = useModel()
const catStore = useCatStore()
const { getSharedMenu } = useSharedMenu()
const modelStore = useModelStore()
@@ -51,12 +51,6 @@ watch(() => catStore.penetrable, (value) => {
appWindow.setIgnoreCursorEvents(value)
}, { immediate: true })
const backgroundImage = computed(() => {
if (!modelStore.currentModel) return
return convertFileSrc(join(modelStore.currentModel.path, 'resources', 'background.png'))
})
function handleWindowDrag() {
appWindow.startDragging()
}
@@ -72,9 +66,7 @@ async function handleContextmenu(event: MouseEvent) {
}
function resolveImagePath(key: string, side: 'left' | 'right' = 'left') {
if (!modelStore.currentModel) return
return convertFileSrc(join(modelStore.currentModel.path, 'resources', `${side}-keys`, `${key}.png`))
return convertFileSrc(join(modelStore.currentModel!.path, 'resources', `${side}-keys`, `${key}.png`))
}
</script>

15
src/utils/dom.ts Normal file
View File

@@ -0,0 +1,15 @@
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
})
}