Interactive Video Annotator JavaScript, HTML
👤 Sharing: AI
```html
<!DOCTYPE html>
<html>
<head>
<title>Interactive Video Annotator</title>
<style>
body {
font-family: sans-serif;
margin: 20px;
}
#video-container {
position: relative;
width: 800px; /* Adjust as needed */
margin-bottom: 20px;
}
#video-element {
width: 100%;
}
#annotation-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: crosshair;
}
#controls {
margin-top: 10px;
}
#annotation-list {
list-style-type: none;
padding: 0;
}
#annotation-list li {
margin-bottom: 5px;
border: 1px solid #ccc;
padding: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.annotation-delete-button {
background-color: #f44336;
color: white;
border: none;
padding: 5px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
cursor: pointer;
}
.annotation-details {
flex-grow: 1;
}
</style>
</head>
<body>
<h1>Interactive Video Annotator</h1>
<div id="video-container">
<video id="video-element" controls width="800">
<source src="your-video.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<canvas id="annotation-canvas"></canvas>
</div>
<div id="controls">
<label for="annotation-text">Annotation Text:</label>
<input type="text" id="annotation-text">
<button id="add-annotation-button">Add Annotation</button>
<button id="clear-canvas-button">Clear Canvas</button>
</div>
<h2>Annotations:</h2>
<ul id="annotation-list">
</ul>
<script>
const video = document.getElementById('video-element');
const canvas = document.getElementById('annotation-canvas');
const ctx = canvas.getContext('2d');
const annotationText = document.getElementById('annotation-text');
const addAnnotationButton = document.getElementById('add-annotation-button');
const clearCanvasButton = document.getElementById('clear-canvas-button');
const annotationList = document.getElementById('annotation-list');
let drawing = false;
let startX, startY;
let annotations = []; // Store annotations as objects (timestamp, rectangle, text)
function resizeCanvas() {
canvas.width = video.offsetWidth;
canvas.height = video.offsetHeight;
}
video.addEventListener('loadedmetadata', () => {
resizeCanvas();
});
window.addEventListener('resize', () => {
resizeCanvas();
});
canvas.addEventListener('mousedown', (e) => {
drawing = true;
startX = e.offsetX;
startY = e.offsetY;
});
canvas.addEventListener('mouseup', (e) => {
if (!drawing) return;
drawing = false;
const width = e.offsetX - startX;
const height = e.offsetY - startY;
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.strokeRect(startX, startY, width, height);
});
canvas.addEventListener('mousemove', (e) => {
if (!drawing) return;
// Redraw the current rectangle being drawn (optional, for a live preview)
resizeCanvas(); //Redraw to clear the old one
redrawAnnotations(); //Redraw existing annotations
const width = e.offsetX - startX;
const height = e.offsetY - startY;
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.strokeRect(startX, startY, width, height);
});
addAnnotationButton.addEventListener('click', () => {
if (startX === undefined || startY === undefined || !drawing) {
alert("Please draw a rectangle first.");
return;
}
const width = canvas.width;
const height = canvas.height;
let endX = 0;
let endY = 0;
canvas.addEventListener("mouseup", (e) => {
endX = e.offsetX;
endY = e.offsetY;
if (annotationText.value.trim() !== "") {
const annotation = {
timestamp: video.currentTime,
rectangle: {
startX: startX,
startY: startY,
width: endX - startX,
height: endY - startY,
},
text: annotationText.value,
};
annotations.push(annotation);
updateAnnotationList();
// Reset drawing flags and clear the annotation text.
startX = undefined;
startY = undefined;
annotationText.value = "";
}else{
alert("Please enter annotation text.");
}
}, {once: true});
// Optionally, clear drawing flags here if you don't want to wait for mouseup
// startX = undefined;
// startY = undefined;
});
clearCanvasButton.addEventListener('click', () => {
clearCanvas();
});
function clearCanvas() {
resizeCanvas(); //Resizes the canvas to its current dimensions, effectively clearing it.
redrawAnnotations();
}
function redrawAnnotations() {
for (const annotation of annotations) {
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.strokeRect(annotation.rectangle.startX, annotation.rectangle.startY, annotation.rectangle.width, annotation.rectangle.height);
}
}
function updateAnnotationList() {
annotationList.innerHTML = ''; // Clear the list
annotations.forEach((annotation, index) => {
const listItem = document.createElement('li');
listItem.innerHTML = `
<div class="annotation-details">
<strong>Time:</strong> ${formatTime(annotation.timestamp)}<br>
<strong>Text:</strong> ${annotation.text}<br>
<strong>Rectangle:</strong> (${annotation.rectangle.startX}, ${annotation.rectangle.startY}, ${annotation.rectangle.width}, ${annotation.rectangle.height})
</div>
<button class="annotation-delete-button" data-index="${index}">Delete</button>
`;
annotationList.appendChild(listItem);
});
// Add event listeners to the delete buttons
document.querySelectorAll('.annotation-delete-button').forEach(button => {
button.addEventListener('click', deleteAnnotation);
});
}
function deleteAnnotation(event) {
const index = event.target.dataset.index;
annotations.splice(index, 1);
updateAnnotationList();
clearCanvas();
redrawAnnotations(); //Redraw after deleting
}
function formatTime(time) {
const minutes = Math.floor(time / 60);
const seconds = Math.floor(time % 60);
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
video.addEventListener('pause', () => {
redrawAnnotations();
});
video.addEventListener('play', () => {
clearCanvas(); // Clear annotations while playing
// Start a timer to redraw annotations every so often (e.g., every 100ms)
// to account for potential frame changes.
redrawAnnotations();
});
video.addEventListener('seeked', () => {
clearCanvas(); // Clear and redraw on seek
redrawAnnotations();
});
</script>
</body>
</html>
```
👁️ Viewed: 8
Comments