Changed around line 1
+ webCamParser
+ extends abstractScrollWithRequirementsParser
+ description Access the device webcam with optional controls for capturing images.
+ cueFromId
+ inScope widthParser heightParser
+ javascript
+ compileInstance() {
+ const id = "webcam" + this._getUid()
+ const width = this.get("width") || "640"
+ const height = this.get("height") || "480"
+ const containerStyle = `
+ .webcamContainer {
+ position: relative;
+ width: ${width}px;
+ margin: 20px auto;
+ }
+ .webcamControls {
+ margin-top: 10px;
+ text-align: center;
+ }
+ .webcamButton {
+ background: #0066cc;
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 4px;
+ margin: 0 5px;
+ cursor: pointer;
+ }
+ .webcamButton:hover {
+ background: #0052a3;
+ }
+ .capturedImage {
+ display: none;
+ margin-top: 10px;
+ }
+ `
+
+ return `
+ ${containerStyle}
+
+
+
+
+
+
+
+
+
+
+ (async () => {
+ const video = document.getElementById('video${id}');
+ const canvas = document.getElementById('canvas${id}');
+ const captureButton = document.getElementById('capture${id}');
+ const retakeButton = document.getElementById('retake${id}');
+ const capturedImage = document.getElementById('capturedImage${id}');
+ const ctx = canvas.getContext('2d');
+
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia({
+ video: {
+ width: { ideal: ${width} },
+ height: { ideal: ${height} }
+ }
+ });
+ video.srcObject = stream;
+ } catch (err) {
+ console.error('Error accessing webcam:', err);
+ return;
+ }
+
+ captureButton.addEventListener('click', () => {
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
+ const imageData = canvas.toDataURL('image/png');
+ capturedImage.src = imageData;
+ video.style.display = 'none';
+ capturedImage.style.display = 'block';
+ captureButton.style.display = 'none';
+ retakeButton.style.display = 'inline-block';
+
+ // Create a custom event with the image data
+ const event = new CustomEvent('imageCaptured', {
+ detail: { imageData, timestamp: new Date().toISOString() }
+ });
+ document.dispatchEvent(event);
+ });
+
+ retakeButton.addEventListener('click', () => {
+ video.style.display = 'block';
+ capturedImage.style.display = 'none';
+ captureButton.style.display = 'inline-block';
+ retakeButton.style.display = 'none';
+ });
+ })();
+
+ `
+ }