diff --git a/client/src/components/LiveOverlay/Nico.vue b/client/src/components/LiveOverlay/Nico.vue index effb4b2..d8dfcf6 100644 --- a/client/src/components/LiveOverlay/Nico.vue +++ b/client/src/components/LiveOverlay/Nico.vue @@ -6,7 +6,7 @@ import { defineComponent, ref } from 'vue' import { connectTarget } from '/@/lib/connect' import useElementSize from '/@/use/elementSize' -import { addComment } from './commentRenderer' +import { useCommentRenderer } from './commentRenderer' import { addReaction } from './reactionRenderer' export default defineComponent({ @@ -20,6 +20,7 @@ export default defineComponent({ setup() { const baseEle = ref() const { height: baseHeight, width: baseWidth } = useElementSize(baseEle) + const { addComment } = useCommentRenderer(baseEle, baseHeight) connectTarget.addEventListener('reaction', e => { if (document.visibilityState === 'hidden') return @@ -29,7 +30,7 @@ export default defineComponent({ connectTarget.addEventListener('comment', e => { if (document.visibilityState === 'hidden') return - addComment(baseEle, baseHeight, e.detail.text) + addComment(e.detail.text) }) return { baseEle } diff --git a/client/src/components/LiveOverlay/commentRenderer.ts b/client/src/components/LiveOverlay/commentRenderer.ts index 7d78c3c..233d47e 100644 --- a/client/src/components/LiveOverlay/commentRenderer.ts +++ b/client/src/components/LiveOverlay/commentRenderer.ts @@ -1,38 +1,59 @@ -import { Ref } from 'vue' +import { computed, ref, Ref } from 'vue' + +/* +- フォントサイズ: 画面に CommentLines 行表示できるサイズ。ただし、最低でも MinimumFontSize px +- コメント表示位置: 上から詰める + - 現状、コメントはその文字長に関わらず画面内にいる間行を専有する(ニコニコでは文字列幅だけ専有している) +*/ const CommentLines = 10 -let commentLineNow = 0 +const MinimumFontSize = 20 +const LineHeight = 1.5 -const incrementCommentLine = () => { - commentLineNow++ - if (commentLineNow === CommentLines) { - commentLineNow = 0 - } +const indexOfMin = (arr: number[]): number => { + const minCount = Math.min(...arr) + return arr.findIndex(o => o === minCount) } -export const addComment = ( +export const useCommentRenderer = ( baseEle: Ref, - baseHeight: Ref, - text: string -): void => { - if (!baseEle.value) return - - const lineHeight = baseHeight.value / CommentLines - - const $comment = document.createElement('div') - $comment.className = 'animation-comment' - $comment.textContent = text - $comment.style.top = `${commentLineNow * lineHeight}px` - $comment.style.fontSize = `${lineHeight}px` - - $comment.addEventListener( - 'animationend', - () => { - $comment.remove() - }, - { once: true } + baseHeight: Ref +): { addComment: (text: string) => void } => { + const countPerLineAll = ref(Array(CommentLines).fill(0)) // 行ごとのコメント数(画面外の行を含む) + + const lineCount = computed(() => + Math.min( + Math.floor(baseHeight.value / (MinimumFontSize * LineHeight)), + CommentLines + ) ) - baseEle.value.append($comment) + const lineHeight = computed(() => baseHeight.value / lineCount.value) + const fontSize = computed(() => lineHeight.value / LineHeight) + + const addComment = (text: string) => { + if (!baseEle.value) return - incrementCommentLine() + const linesInScreen = countPerLineAll.value.slice(0, lineCount.value) + const index = indexOfMin(linesInScreen) + const top = index * lineHeight.value + + countPerLineAll.value[index]++ + + const $comment = document.createElement('div') + $comment.className = 'animation-comment' + $comment.textContent = text + $comment.style.top = `${top}px` + $comment.style.fontSize = `${fontSize.value}px` + + $comment.addEventListener( + 'animationend', + () => { + $comment.remove() + countPerLineAll.value[index]-- + }, + { once: true } + ) + baseEle.value.append($comment) + } + return { addComment } }