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