/******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ // The require scope /******/ var __webpack_require__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; /* unused harmony export ScreenshotAnnotator */ class ScreenshotAnnotator { constructor() { this.canvas = null; this.currentTool = 'brush'; this.currentColor = '#ff0000'; this.currentSize = 5; this.drawingMode = true; } initialize(imageUrl, container) { console.log('Initializing annotator with container:', container); return new Promise((resolve, reject) => { try { // Create canvas container const canvasContainer = document.createElement('div'); canvasContainer.className = 'canvas-container'; // Create toolbar const toolbar = document.createElement('div'); toolbar.className = 'annotation-toolbar'; toolbar.innerHTML = `
`; // Create canvas wrapper for scrolling const canvasWrapper = document.createElement('div'); canvasWrapper.className = 'canvas-wrapper'; // Create canvas const canvas = document.createElement('canvas'); canvas.style.margin = 'auto'; canvas.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)'; // Add elements to DOM canvasWrapper.appendChild(canvas); canvasContainer.appendChild(toolbar); canvasContainer.appendChild(canvasWrapper); container.appendChild(canvasContainer); console.log('Creating Fabric canvas'); // Initialize Fabric canvas this.canvas = new Canvas(canvas); // Load image console.log('Loading image:', imageUrl.substring(0, 100) + '...'); const img = new window.Image(); img.onerror = error => { console.error('Error loading image:', error); reject(error); }; img.onload = () => { console.log('Image loaded:', img.width, 'x', img.height); try { // Set canvas size to match window size while maintaining aspect ratio const maxWidth = window.innerWidth - 40; const maxHeight = window.innerHeight - 100; const scale = Math.min(maxWidth / img.width, maxHeight / img.height); const width = img.width * scale; const height = img.height * scale; console.log('Setting canvas size:', width, 'x', height); this.canvas.setWidth(width); this.canvas.setHeight(height); // Create Fabric image console.log('Creating Fabric image'); Image.fromURL(imageUrl, fabricImg => { try { fabricImg.scale(scale); fabricImg.selectable = false; // Add image to canvas this.canvas.add(fabricImg); this.canvas.renderAll(); // Set up event listeners this.setupEventListeners(toolbar); console.log('Setup complete'); // Return promise that resolves when done button is clicked document.getElementById('done-btn').addEventListener('click', () => { try { const dataUrl = this.canvas.toDataURL(); this.cleanup(); resolve(dataUrl); } catch (error) { console.error('Error getting data URL:', error); reject(error); } }); } catch (error) { console.error('Error setting up Fabric image:', error); reject(error); } }); } catch (error) { console.error('Error in image onload:', error); reject(error); } }; img.src = imageUrl; } catch (error) { console.error('Error in initialize:', error); reject(error); } }); } setupEventListeners(toolbar) { console.log('Setting up event listeners'); try { // Tool buttons const toolButtons = toolbar.querySelectorAll('.tool-btn'); toolButtons.forEach(button => { button.addEventListener('click', () => { toolButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); this.currentTool = button.dataset.tool; this.canvas.isDrawingMode = this.currentTool === 'brush'; }); }); // Color picker const colorPicker = document.getElementById('color-picker'); colorPicker.addEventListener('change', e => { this.currentColor = e.target.value; if (this.canvas.isDrawingMode) { this.canvas.freeDrawingBrush.color = this.currentColor; } }); // Size slider const sizeSlider = document.getElementById('size-slider'); sizeSlider.addEventListener('input', e => { this.currentSize = parseInt(e.target.value); if (this.canvas.isDrawingMode) { this.canvas.freeDrawingBrush.width = this.currentSize; } }); // Undo button document.getElementById('undo-btn').addEventListener('click', () => { const objects = this.canvas.getObjects(); if (objects.length > 1) { // Keep background image this.canvas.remove(objects[objects.length - 1]); } }); // Clear button document.getElementById('clear-btn').addEventListener('click', () => { const objects = this.canvas.getObjects(); // Remove all objects except background image for (let i = objects.length - 1; i > 0; i--) { this.canvas.remove(objects[i]); } }); // Set initial brush settings this.canvas.freeDrawingBrush.color = this.currentColor; this.canvas.freeDrawingBrush.width = this.currentSize; // Mouse down handler for shapes and text this.canvas.on('mouse:down', options => { if (this.canvas.isDrawingMode) return; const pointer = this.canvas.getPointer(options.e); const startX = pointer.x; const startY = pointer.y; switch (this.currentTool) { case 'rectangle': const rect = new Rect({ left: startX, top: startY, width: 0, height: 0, fill: 'transparent', stroke: this.currentColor, strokeWidth: this.currentSize }); this.canvas.add(rect); this.canvas.setActiveObject(rect); break; case 'arrow': const line = new Line([startX, startY, startX, startY], { stroke: this.currentColor, strokeWidth: this.currentSize }); this.canvas.add(line); this.canvas.setActiveObject(line); break; case 'text': const text = new IText('Type here...', { left: startX, top: startY, fill: this.currentColor, fontSize: this.currentSize * 3 }); this.canvas.add(text); text.enterEditing(); text.selectAll(); break; } }); // Mouse move handler for shapes this.canvas.on('mouse:move', options => { if (!this.canvas.isDrawingMode && this.canvas.getActiveObject()) { const pointer = this.canvas.getPointer(options.e); const activeObj = this.canvas.getActiveObject(); if (this.currentTool === 'rectangle') { const width = pointer.x - activeObj.left; const height = pointer.y - activeObj.top; activeObj.set({ width, height }); } else if (this.currentTool === 'arrow') { const points = [activeObj.x1, activeObj.y1, pointer.x, pointer.y]; activeObj.set({ x2: pointer.x, y2: pointer.y }); } this.canvas.renderAll(); } }); // Mouse up handler this.canvas.on('mouse:up', () => { this.canvas.setActiveObject(null); }); } catch (error) { console.error('Error in setupEventListeners:', error); throw error; } } cleanup() { try { // Remove event listeners and clean up resources if (this.canvas) { this.canvas.dispose(); this.canvas = null; } } catch (error) { console.error('Error in cleanup:', error); } } } /******/ })() ;