Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: キャラクター一覧をキャッシュして、2回目以降の表示にかかる時間を短くする #1994

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions src/components/CharacterButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
:disable="uiLocked"
:class="{ opaque: loading }"
aria-haspopup="menu"
@click="
() => {
updateMenuHeight();
openMenu();
}
"
>
<!-- q-imgだとdisableのタイミングで点滅する -->
<div class="icon-container">
Expand All @@ -22,13 +28,9 @@
<div v-if="loading" class="loading">
<QSpinner color="primary" size="1.6rem" :thickness="7" />
</div>
<QMenu
class="character-menu"
transition-show="none"
transition-hide="none"
:max-height="maxMenuHeight"
@before-show="updateMenuHeight"
>
</QBtn>
<Teleport to="#character-icon-teleport">
<div v-if="hasMenuOpen" class="character-menu">
<QList style="min-width: max-content" class="character-item-container">
<QItem
v-if="selectedStyleInfo == undefined && !emptiable"
Expand Down Expand Up @@ -104,7 +106,6 @@
<!-- スタイルが2つ以上あるものだけ、スタイル選択ボタンを表示する-->
<template v-if="characterInfo.metas.styles.length >= 2">
<QSeparator vertical />

<div
class="flex items-center q-px-sm q-py-none cursor-pointer"
:class="
Expand Down Expand Up @@ -188,13 +189,13 @@
</QBtnGroup>
</QItem>
</QList>
</QMenu>
</QBtn>
</div>
</Teleport>
</template>

<script setup lang="ts">
import { debounce, QBtn } from "quasar";
import { computed, Ref, ref } from "vue";
import { computed, CSSProperties, Ref, ref } from "vue";
import { base64ImageToUri } from "@/helpers/imageHelper";
import { useStore } from "@/store";
import { CharacterInfo, SpeakerId, Voice } from "@/type/preload";
Expand Down Expand Up @@ -297,7 +298,6 @@ const getDefaultStyle = (speakerUuid: SpeakerId) => {
) ?? characterInfo?.metas.styles[0]; // デフォルトのスタイルIDが見つからない場合stylesの先頭を選択する

if (defaultStyle == undefined) throw new Error("defaultStyle == undefined");

return defaultStyle;
};

Expand All @@ -309,7 +309,6 @@ const onSelectSpeaker = (speakerUuid: SpeakerId) => {
styleId: style.styleId,
});
};

const subMenuOpenFlags = ref(
[...Array(props.characterInfos.length)].map(() => false)
);
Expand All @@ -336,6 +335,38 @@ const updateMenuHeight = () => {
// pxで指定するとウインドウサイズ変更に追従できないので ウインドウの高さの96% - ボタンの下端の座標 でメニューの高さを決定する。
maxMenuHeight.value = `max(170px, min(${heightLimit}, calc(96vh - ${buttonRect.bottom}px)))`;
};

const hasMenuOpen = ref(false);
const shouldShowMenu: Ref<CSSProperties["visibility"]> = ref("hidden");
const menuPosition = ref({ top: 0, left: 0 });
const menuPositionTopStyle = computed(() => `${menuPosition.value.top}px`);
const menuPositionLeftStyle = computed(() => `${menuPosition.value.left}px`);

const hideMenu = debounce(() => {
document.removeEventListener("click", hideMenu, { capture: true });
shouldShowMenu.value = "hidden";
}, 50);
const showMenu = debounce(() => {
document.addEventListener("click", hideMenu, { capture: true });
shouldShowMenu.value = "visible";
}, 50);

const openMenu = () => {
hasMenuOpen.value = true;

if (buttonRef.value == undefined)
throw new Error("buttonRef.value == undefined");
const el = buttonRef.value.$el;
if (!(el instanceof Element)) throw new Error("!(el instanceof Element)");
const buttonRect = el.getBoundingClientRect();
menuPosition.value = { top: buttonRect.bottom, left: buttonRect.left };

if (shouldShowMenu.value === "hidden") {
showMenu();
} else {
hideMenu();
}
};
</script>

<style scoped lang="scss">
Expand Down Expand Up @@ -383,6 +414,15 @@ const updateMenuHeight = () => {
}

.character-menu {
position: fixed;
overflow-y: scroll;
background: colors.$background;
max-height: v-bind(maxMenuHeight);
visibility: v-bind(shouldShowMenu);
top: v-bind(menuPositionTopStyle);
left: v-bind(menuPositionLeftStyle);
z-index: 10;

.character-item-container {
display: flex;
flex-direction: column;
Expand Down
1 change: 1 addition & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<strong>JavaScriptが無効化されている環境では動作しません。</strong>
</noscript>
<div id="app" style="height: 100%"></div>
<div id="character-icon-teleport"></div>
<script type="module">
// https://stackoverflow.com/questions/70714690/buffer-is-not-defined-in-react-vite#:~:text=installing%20buffer%20as%20a%20dev%20dependency%20yarn%20add%20buffer%20(use%20npm%20equivalent%20if%20you%20use%20npm)
import { Buffer } from "buffer";
Expand Down
Loading