最初コミット

このコミットが含まれているのは:
守矢諏訪子 2023-12-18 15:22:34 +09:00
コミット 5e5becb592
7個のファイルの変更15724行の追加0行の削除

103
comments.json ノーマルファイル
ファイルの表示

@ -0,0 +1,103 @@
[
{ "id": 1, "timestamp": 0, "text": "くねくね" },
{ "id": 1, "timestamp": 0, "text": "アンダイン" },
{ "id": 1, "timestamp": 0, "text": "2号兄貴リスペクト" },
{ "id": 1, "timestamp": 1, "text": "カミナリ" },
{ "id": 1, "timestamp": 1, "text": "あー生き返れ生き返れ" },
{ "id": 2, "timestamp": 2, "text": "サイコキネシス" },
{ "id": 3, "timestamp": 3, "text": "バッグマン" },
{ "id": 3, "timestamp": 3, "text": "パ ッ ク マ ン" },
{ "id": 3, "timestamp": 3, "text": "ドンキーコング" },
{ "id": 3, "timestamp": 3, "text": "ビンビンビンビン" },
{ "id": 3, "timestamp": 3, "text": " B" },
{ "id": 3, "timestamp": 4, "text": "ビュインビュインビュインビュインビュイン" },
{ "id": 3, "timestamp": 4, "text": "787B" },
{ "id": 3, "timestamp": 5, "text": "wwwwwwwwwwwwww" },
{ "id": 3, "timestamp": 5, "text": "ここすき" },
{ "id": 3, "timestamp": 5, "text": "ワカメ" },
{ "id": 3, "timestamp": 5, "text": "草" },
{ "id": 3, "timestamp": 6, "text": "草" },
{ "id": 3, "timestamp": 7, "text": "チ↑クッ↓" },
{ "id": 3, "timestamp": 7, "text": "デクナッツで草" },
{ "id": 3, "timestamp": 7, "text": "アロアロアロアロアロアロアロアロアロアロアロアロアロアロ" },
{ "id": 3, "timestamp": 8, "text": "" },
{ "id": 3, "timestamp": 8, "text": "サルディニア訛りは草" },
{ "id": 3, "timestamp": 8, "text": "デクナッツ" },
{ "id": 3, "timestamp": 9, "text": "wwwwwwwwwwwwwwwwwwwwwwww" },
{ "id": 3, "timestamp": 9, "text": "デカクサン" },
{ "id": 3, "timestamp": 9, "text": "ここ怪盗ヒマラ" },
{ "id": 4, "timestamp": 11, "text": "呪物やめろ" },
{ "id": 4, "timestamp": 11, "text": "ムウマージ確認してたらちょっと似てた" },
{ "id": 4, "timestamp": 11, "text": "草" },
{ "id": 4, "timestamp": 11, "text": "残念!はずれだヨ!" },
{ "id": 4, "timestamp": 11, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "ワ ソ チ 〜 ユ ン グ ?" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "学校などの教育用機械のクイズではずれた音" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "へっぽこBGM" },
{ "id": 4, "timestamp": 12, "text": "?????????" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "ウンチーコングって知ってる?" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "ウ ン チ ー コ ン グ ?" },
{ "id": 4, "timestamp": 12, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 12, "text": "チョイーン" },
{ "id": 4, "timestamp": 12, "text": "ウ ン チ ~ コ ン グ ?" },
{ "id": 4, "timestamp": 12, "text": "草" },
{ "id": 4, "timestamp": 12, "text": "クソザコナメクジ" },
{ "id": 4, "timestamp": 12, "text": "へな  ち ょ こ ん ぐ" },
{ "id": 4, "timestamp": 12, "text": "????????????" },
{ "id": 4, "timestamp": 12, "text": "くっそw" },
{ "id": 4, "timestamp": 12, "text": "草" },
{ "id": 4, "timestamp": 12, "text": "ここすき" },
{ "id": 4, "timestamp": 12, "text": "ポョヨヨヨヨ~ン" },
{ "id": 4, "timestamp": 12, "text": "情けない音で草" },
{ "id": 4, "timestamp": 12, "text": "ブレインスキャン開始" },
{ "id": 4, "timestamp": 12, "text": "ぽよよ~ん" },
{ "id": 4, "timestamp": 13, "text": "√33-√4" },
{ "id": 4, "timestamp": 13, "text": "チュイーン(笑)" },
{ "id": 4, "timestamp": 13, "text": "??????????" },
{ "id": 4, "timestamp": 13, "text": "?????????????????" },
{ "id": 4, "timestamp": 13, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 13, "text": "??????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 13, "text": "???????????????????????????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 13, "text": "????????????????????????????" },
{ "id": 4, "timestamp": 13, "text": "????????????????????????????????????" },
{ "id": 4, "timestamp": 13, "text": "草" },
{ "id": 4, "timestamp": 13, "text": "????????????????????????????" },
{ "id": 4, "timestamp": 13, "text": "ちょい~~んwwww" },
{ "id": 4, "timestamp": 14, "text": "????????????????????????????????????" },
{ "id": 4, "timestamp": 14, "text": "????????????????????????????????????????????????????" },
{ "id": 4, "timestamp": 14, "text": "音で草" },
{ "id": 4, "timestamp": 14, "text": "へ な ち ょ こ" },
{ "id": 4, "timestamp": 14, "text": "ギーグ" },
{ "id": 4, "timestamp": 13, "text": "草" },
{ "id": 4, "timestamp": 15, "text": "ここすき" },
{ "id": 4, "timestamp": 15, "text": "????????????????????" },
{ "id": 4, "timestamp": 15, "text": "ハピ森の家具動かすときに鳴るSE" },
{ "id": 4, "timestamp": 15, "text": "どう森の家具置けない音" },
{ "id": 4, "timestamp": 15, "text": "旗" },
{ "id": 4, "timestamp": 15, "text": "くねくね" },
{ "id": 4, "timestamp": 15, "text": "文字ノリノリでワロタ" },
{ "id": 4, "timestamp": 15, "text": "わかめ" },
{ "id": 4, "timestamp": 16, "text": "いや、コンブ" },
{ "id": 4, "timestamp": 16, "text": "ワカメ" },
{ "id": 4, "timestamp": 16, "text": "文字左右にいってるの草" },
{ "id": 4, "timestamp": 17, "text": "マイクラでフグ食べたときになるやつ" },
{ "id": 4, "timestamp": 17, "text": "ここで耐えられなかった" },
{ "id": 4, "timestamp": 17, "text": "ここで耐えられなかった" },
{ "id": 4, "timestamp": 17, "text": "こわE" },
{ "id": 4, "timestamp": 17, "text": "男すき" },
{ "id": 4, "timestamp": 18, "text": "wwwwww" },
{ "id": 4, "timestamp": 19, "text": "どう森マジわかるwwwww" },
{ "id": 4, "timestamp": 19, "text": "草" },
{ "id": 4, "timestamp": 19, "text": "頭おかしなるで" },
{ "id": 4, "timestamp": 19, "text": "薬  物  中  毒  者" },
{ "id": 4, "timestamp": 21, "text": "サルディニア訛り" },
{ "id": 4, "timestamp": 22, "text": "マリカでサンダー食らうとこんなんなるよね" }
]

27
index.html ノーマルファイル
ファイルの表示

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>動画</title>
<script src="vue.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="root">
<div ref="videoContainer" class="video-container">
<video ref="videoPlayer" @timeupdate="updateComments" controls>
<source :src="videoOgv" type="video/ogg" />
<source :src="videoWebm" type="video/webm" />
このブラウザは&lt;video&gt;タグが対応していません。
</video>
<div class="comments-overlay" v-if="comments.length">
<div v-for="comment in visibleComments" :key="comment.id" class="comment" :style="{ top: comment.yPos + 'px', animation: comment.animationStyle }">
{{ comment.text }}
</div>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>

130
index.js ノーマルファイル
ファイルの表示

@ -0,0 +1,130 @@
const player = Vue.createApp({
data() {
return {
videoOgv: 'video.ogv',
videoWebm: 'video.webm',
commentJson: 'comments.json',
comments: [],
visibleComments: [],
containerWidth: 0
};
},
methods: {
async loadComments() {
try {
const resp = await fetch("comments.json");
if (!resp.ok) {
throw new Error(`HTTPエラー: ${resp.status}`);
}
const data = await resp.json();
this.comments = data.map((comment, index) => {
return { ...comment, yPos: (index % 10) * 30 };
});
} catch (error) {
console.error("コメントを受取に失敗:", error);
}
},
updateComments() {
const currentTime = this.$refs.videoPlayer.currentTime;
let yPos = 0;
this.visibleComments = this.comments.filter(comment => {
const isVisible = currentTime >= comment.timestamp && currentTime <= (comment.timestamp + 5);
if (isVisible && typeof comment.yPos === 'undefined') {
comment.yPos = yPos;
yPos += 30;
}
return isVisible;
});
this.$nextTick(() => {
this.animateComments();
});
},
animateComments() {
const commentsElements = this.$refs.videoContainer.querySelectorAll('.comment');
commentsElements.forEach(el => {
const commentWidth = el.offsetWidth;
let totalDistance = this.containerWidth + commentWidth;
totalDistance -= (100-commentWidth);
el.style.transition = 'transform 5s linear';
el.style.transform = `translateX(-${totalDistance}px)`;
});
},
updateContainerWidth() {
const container = this.$refs.videoContainer;
this.containerWidth = container ? container.offsetWidth : 0;
},
calculateCommentWidth(text) {
const tempDiv = document.createElement("div");
tempDiv.style.position = "absolute";
tempDiv.style.whiteSpace = "nowrap";
tempDiv.style.fontSize = "50px";
tempDiv.textContent = text;
document.body.appendChild(tempDiv);
const width = tempDiv.clientWidth;
document.body.removeChild(tempDiv);
return width;
},
createAnimationKeyframes() {
const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.innerHTML = `
@keyframes scrollComment {
from { transform: translateX(${this.containerWidth}px); }
to { transform: translateX(-${this.containerWidth}px); }
}
`;
document.head.appendChild(styleSheet);
},
pauseComments() {
const commentsElements = this.$refs.videoContainer.querySelectorAll('.comment');
commentsElements.forEach(el => {
const computedStyle = window.getComputedStyle(el);
const transform = computedStyle.transform || computedStyle.webkitTransform;
el.style.transform = transform;
el.style.transition = 'none';
});
},
playComments() {
this.animateComments();
},
attachVideoEventListeners() {
const videoPlayer = this.$refs.videoPlayer;
videoPlayer.addEventListener('play', this.playComments);
videoPlayer.addEventListener('pause', this.pauseComments);
}
},
mounted() {
this.loadComments();
this.createAnimationKeyframes();
window.addEventListener('resize', () => {
this.updateContainerWidth();
this.createAnimationKeyframes();
});
this.updateContainerWidth();
this.attachVideoEventListeners();
window.addEventListener('resize', this.updateContainerWidth);
},
beforeUnmount() {
window.removeEventListener('resize', this.updateContainerWidth);
},
computed: {
commentAnimationStyle() {
return `
<style>
@keyframes scrollComment {
from { transform: translateX(0%); }
to { transform: translateX(-${this.containerWidth}px); }
}
</style>
`;
}
}
});
player.mount("#root");

35
style.css ノーマルファイル
ファイルの表示

@ -0,0 +1,35 @@
.video-container {
position: relative;
max-width: 900px;
margin: auto;
}
video {
width: 100%;
height: auto;
}
.comments-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
overflow: hidden;
pointer-events: none;
}
.comment {
color: #fcfcfc;
position: absolute;
white-space: nowrap;
right: 0;
font-size: 50px;
text-shadow: -1px 1px 0 #232629, 1px 1px 0 #232629, 1px -1px 0 #232629, -1px -1px 0 #232629;
}
@keyframes scrollComment {
from { transform: translateX(1800px); }
to { transform: translateX(-1800px); }
}

バイナリ
video.ogv ノーマルファイル

バイナリファイルは表示されません。

バイナリ
video.webm ノーマルファイル

バイナリファイルは表示されません。

15429
vue.js ノーマルファイル

ファイル差分が大きすぎるため省略します 差分を読み込み