|
|
|
|
@ -8,8 +8,8 @@ let videosToLoad = 2
|
|
|
|
|
const maxVideosToLoad = 9 |
|
|
|
|
const videos = [] |
|
|
|
|
let videosLoaded = 0 |
|
|
|
|
let aspectRatio = 1 |
|
|
|
|
|
|
|
|
|
let aspectRatio = 1 |
|
|
|
|
let cachedVideos = [] |
|
|
|
|
|
|
|
|
|
let showText = true |
|
|
|
|
@ -24,6 +24,7 @@ const parameterStore = {
|
|
|
|
|
blur: 0, |
|
|
|
|
}, |
|
|
|
|
transformParams: { |
|
|
|
|
scale: 1, |
|
|
|
|
// Additional parameters specific to the tile mode or other transformation
|
|
|
|
|
tilePositionX: 0, // X-coordinate for positioning the tiled video
|
|
|
|
|
tilePositionY: 0, // Y-coordinate for positioning the tiled video
|
|
|
|
|
@ -54,7 +55,7 @@ function applyPreset(presetName) {
|
|
|
|
|
for (const [category, categoryParams] of Object.entries(preset)) { |
|
|
|
|
// Check if the category exists in the parameter store
|
|
|
|
|
if (parameterStore.hasOwnProperty(category)) { |
|
|
|
|
// Iterate over each parameter in the preset
|
|
|
|
|
// Iterate over each parameter in the category
|
|
|
|
|
for (const [paramKey, paramValue] of Object.entries(categoryParams)) { |
|
|
|
|
// Update the corresponding parameter in the parameter store
|
|
|
|
|
parameterStore[category][paramKey] = paramValue; |
|
|
|
|
@ -78,6 +79,11 @@ function debugLog(...args) {
|
|
|
|
|
|
|
|
|
|
function loadVideos(num) { |
|
|
|
|
debugLog(`Loading ${num} videos`) |
|
|
|
|
if (num < 0) { |
|
|
|
|
num = Math.max(num,-Math.abs(maxVideosToLoad)) |
|
|
|
|
} else { |
|
|
|
|
num = Math.min(num,Math.abs(maxVideosToLoad)) |
|
|
|
|
} |
|
|
|
|
while (num > 0) { |
|
|
|
|
let video = createVideoElement() |
|
|
|
|
video.addEventListener("loadedmetadata", handleVideoLoaded) |
|
|
|
|
@ -91,15 +97,11 @@ function loadVideos(num) {
|
|
|
|
|
let video = videos.pop() |
|
|
|
|
video.removeEventListener("loadedmetadata", handleVideoLoaded) |
|
|
|
|
video.removeEventListener("ended", handleVideoEnded) |
|
|
|
|
video.removeEventListener("error", handleVideoEnded) |
|
|
|
|
num++ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
videos.forEach((video) => { |
|
|
|
|
video.addEventListener("loadedmetadata", handleVideoLoaded) |
|
|
|
|
video.addEventListener("ended", handleVideoEnded) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
function createVideoElement() { |
|
|
|
|
const video = document.createElement("video") |
|
|
|
|
video.autoplay = true |
|
|
|
|
@ -124,8 +126,6 @@ function handleVideoEnded(event) {
|
|
|
|
|
function drawVideos() { |
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height) |
|
|
|
|
|
|
|
|
|
let blendModes = ["screen","overlay","difference","lighten"] |
|
|
|
|
|
|
|
|
|
videos.forEach((video,i) => { |
|
|
|
|
// Calculate scaling factor to fit the canvas
|
|
|
|
|
const scale = Math.max(canvas.width/video.videoWidth, canvas.height/video.videoHeight) |
|
|
|
|
@ -142,8 +142,11 @@ function drawVideos() {
|
|
|
|
|
if (i === 0) { |
|
|
|
|
ctx.globalCompositeOperation = "source-over" |
|
|
|
|
} else { |
|
|
|
|
ctx.globalCompositeOperation = blendModes[i % blendModes.length] |
|
|
|
|
// Using values from parameterStore
|
|
|
|
|
ctx.globalCompositeOperation = parameterStore.blendModeParams.mode |
|
|
|
|
ctx.globalAlpha = parameterStore.blendModeParams.opacity |
|
|
|
|
} |
|
|
|
|
video.globalCompositeOperation = ctx.globalCompositeOperation || "default" |
|
|
|
|
|
|
|
|
|
// Draw the current video frame onto the canvas
|
|
|
|
|
ctx.drawImage(video, offsetX, offsetY, scaledWidth, scaledHeight) |
|
|
|
|
@ -179,13 +182,14 @@ function drawDebugText() {
|
|
|
|
|
ctx.textBaseline = "top"; |
|
|
|
|
|
|
|
|
|
// Draw the active preset text
|
|
|
|
|
ctx.fillText(presetText, positionX, positionY); |
|
|
|
|
ctx.fillText(`${presetText}`, positionX, positionY); |
|
|
|
|
ctx.fillText(`${canvas.width}x${canvas.height} (${aspectRatio.toFixed(2)})`, positionX, positionY+20); |
|
|
|
|
|
|
|
|
|
let corners = [[0, 0], [1, 1], [0, 1], [1, 0]]; // Top-left, bottom-right, top-right, bottom-left
|
|
|
|
|
let corners = [[0, 0], [1, 1], [0, 1], [1, 0]]; // Top-left, bottom-right, bottom-left, top-right
|
|
|
|
|
|
|
|
|
|
videos.forEach((video, i) => { |
|
|
|
|
// Get the corner coordinates for the current video
|
|
|
|
|
const corner = corners[i] |
|
|
|
|
const corner = corners[i % corners.length] |
|
|
|
|
|
|
|
|
|
// Calculate the position of the text in the corner
|
|
|
|
|
let positionX = corner[0] ? canvas.width : padding |
|
|
|
|
@ -203,6 +207,7 @@ function drawDebugText() {
|
|
|
|
|
ctx.fillText(getFilename(video.src), positionX, positionY) |
|
|
|
|
ctx.fillText(`Dimensions: ${video.videoWidth}x${video.videoHeight} ()`, positionX, positionY + 20) |
|
|
|
|
ctx.fillText(formatTime(video.currentTime) + "/" + formatTime(video.duration), positionX, positionY + 40) |
|
|
|
|
ctx.fillText(`${video.globalCompositeOperation}` ,positionX,positionY+60) |
|
|
|
|
// Add more debug information as needed
|
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
@ -213,22 +218,27 @@ function getFilename(src) {
|
|
|
|
|
return decodeURIComponent(parts[parts.length - 1].replace(/\%20/g, ' ')) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Helper function to format time in HH:MM:SS format
|
|
|
|
|
function formatTime(seconds) { |
|
|
|
|
const hours = Math.floor(seconds / 3600) |
|
|
|
|
const minutes = Math.floor((seconds % 3600) / 60) |
|
|
|
|
const remainingSeconds = Math.floor(seconds % 60) |
|
|
|
|
return `${(hours?hours.toString().padStart(2, '0')+':':'')}${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}` |
|
|
|
|
const hours = Math.floor(seconds / 3600); |
|
|
|
|
const minutes = Math.floor((seconds % 3600) / 60); |
|
|
|
|
const remainingSeconds = Math.floor(seconds % 60); |
|
|
|
|
return `${(hours ? hours.toString().padStart(2, '0') + ':' : '')}` + |
|
|
|
|
`${minutes.toString().padStart(2, '0')}:`+ |
|
|
|
|
`${remainingSeconds.toString().padStart(2, '0')}`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function updateCanvasSize() { |
|
|
|
|
aspectRatio = Math.max( |
|
|
|
|
videos[0].videoWidth / videos[0].videoHeight, |
|
|
|
|
videos[1].videoWidth / videos[1].videoHeight |
|
|
|
|
) |
|
|
|
|
let maxAspectRatio = 0; |
|
|
|
|
|
|
|
|
|
// Calculate the maximum aspect ratio among all videos
|
|
|
|
|
for (let i = 0; i < videos.length; i++) { |
|
|
|
|
const videoAspectRatio = videos[i].videoWidth / videos[i].videoHeight; |
|
|
|
|
maxAspectRatio = Math.max(maxAspectRatio, videoAspectRatio); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
canvas.width = window.innerWidth |
|
|
|
|
canvas.height = window.innerWidth / aspectRatio |
|
|
|
|
canvas.width = window.innerWidth; |
|
|
|
|
canvas.height = window.innerWidth / maxAspectRatio; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
window.addEventListener("resize", updateCanvasSize) |
|
|
|
|
@ -268,7 +278,6 @@ function selectRandomVideo(videoElement) {
|
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', function(event) { |
|
|
|
|
console.log('keyDown',event) |
|
|
|
|
// Check if the pressed key is the one you want to bind
|
|
|
|
|
if (event.key === 'Enter') { |
|
|
|
|
showText = !showText |
|
|
|
|
} |
|
|
|
|
|