Restore three-button capture interface: Share Entire Screen, Snip, Cancel
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Screen Capture Tool
|
||||
* Captures a screenshot from the user's screen using the Screen Capture API
|
||||
*
|
||||
* @module ScreenCapture
|
||||
*/
|
||||
|
||||
(function() {
|
||||
console.log('Starting Screen Capture Tool initialization...');
|
||||
|
||||
window.captureScreenshot = async function() {
|
||||
console.log('captureScreenshot called');
|
||||
try {
|
||||
// Request screen capture from user
|
||||
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: { mediaSource: 'screen' }
|
||||
});
|
||||
|
||||
// Create video element to capture frame
|
||||
const video = document.createElement('video');
|
||||
video.srcObject = mediaStream;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
video.onloadedmetadata = () => {
|
||||
// Create canvas and draw video frame
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(video, 0, 0);
|
||||
|
||||
// Stop all media tracks
|
||||
mediaStream.getTracks().forEach(track => track.stop());
|
||||
|
||||
// Return canvas for further processing
|
||||
resolve(canvas);
|
||||
};
|
||||
|
||||
video.play();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Screenshot capture failed:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
window.captureSnip = async function() {
|
||||
console.log('captureSnip called');
|
||||
try {
|
||||
// First, get the full screen capture
|
||||
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: { mediaSource: 'screen' }
|
||||
});
|
||||
|
||||
// Create video element to capture frame
|
||||
const video = document.createElement('video');
|
||||
video.srcObject = mediaStream;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
video.onloadedmetadata = () => {
|
||||
// Capture full screen to canvas
|
||||
const fullCanvas = document.createElement('canvas');
|
||||
fullCanvas.width = video.videoWidth;
|
||||
fullCanvas.height = video.videoHeight;
|
||||
const fullCtx = fullCanvas.getContext('2d');
|
||||
fullCtx.drawImage(video, 0, 0);
|
||||
|
||||
// Stop video tracks
|
||||
mediaStream.getTracks().forEach(track => track.stop());
|
||||
|
||||
// Show selection overlay
|
||||
createSelectionOverlay(fullCanvas, resolve);
|
||||
};
|
||||
|
||||
video.play();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Snip capture failed:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
function createSelectionOverlay(fullCanvas, resolve) {
|
||||
console.log('createSelectionOverlay called');
|
||||
// Create overlay container
|
||||
const overlay = document.createElement('div');
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
cursor: crosshair;
|
||||
z-index: 99999;
|
||||
user-select: none;
|
||||
`;
|
||||
|
||||
// Create canvas for drawing selection box
|
||||
const selectionCanvas = document.createElement('canvas');
|
||||
selectionCanvas.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: crosshair;
|
||||
z-index: 100000;
|
||||
`;
|
||||
selectionCanvas.width = window.innerWidth;
|
||||
selectionCanvas.height = window.innerHeight;
|
||||
|
||||
// Scale factor for mapping screen pixels to window pixels
|
||||
const scaleX = fullCanvas.width / window.innerWidth;
|
||||
const scaleY = fullCanvas.height / window.innerHeight;
|
||||
|
||||
let isDrawing = false;
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let endX = 0;
|
||||
let endY = 0;
|
||||
|
||||
const ctx = selectionCanvas.getContext('2d');
|
||||
|
||||
function drawSelection() {
|
||||
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
|
||||
|
||||
if (!isDrawing && (startX === endX && startY === endY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const x = Math.min(startX, endX);
|
||||
const y = Math.min(startY, endY);
|
||||
const width = Math.abs(endX - startX);
|
||||
const height = Math.abs(endY - startY);
|
||||
|
||||
// Draw selection rectangle
|
||||
ctx.strokeStyle = '#0EA5E9';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeRect(x, y, width, height);
|
||||
|
||||
// Fill with semi-transparent color
|
||||
ctx.fillStyle = 'rgba(14, 165, 233, 0.1)';
|
||||
ctx.fillRect(x, y, width, height);
|
||||
|
||||
// Draw corner handles
|
||||
const handleSize = 8;
|
||||
ctx.fillStyle = '#0EA5E9';
|
||||
ctx.fillRect(x - handleSize / 2, y - handleSize / 2, handleSize, handleSize);
|
||||
ctx.fillRect(x + width - handleSize / 2, y - handleSize / 2, handleSize, handleSize);
|
||||
ctx.fillRect(x - handleSize / 2, y + height - handleSize / 2, handleSize, handleSize);
|
||||
ctx.fillRect(x + width - handleSize / 2, y + height - handleSize / 2, handleSize, handleSize);
|
||||
}
|
||||
|
||||
selectionCanvas.addEventListener('mousedown', (e) => {
|
||||
isDrawing = true;
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
endX = startX;
|
||||
endY = startY;
|
||||
});
|
||||
|
||||
selectionCanvas.addEventListener('mousemove', (e) => {
|
||||
if (isDrawing) {
|
||||
endX = e.clientX;
|
||||
endY = e.clientY;
|
||||
drawSelection();
|
||||
}
|
||||
});
|
||||
|
||||
selectionCanvas.addEventListener('mouseup', () => {
|
||||
if (isDrawing) {
|
||||
isDrawing = false;
|
||||
|
||||
const x = Math.min(startX, endX);
|
||||
const y = Math.min(startY, endY);
|
||||
const width = Math.abs(endX - startX);
|
||||
const height = Math.abs(endY - startY);
|
||||
|
||||
// Validate selection
|
||||
if (width < 10 || height < 10) {
|
||||
console.warn('Selection too small');
|
||||
cleanup();
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create cropped canvas from full screenshot
|
||||
const croppedCanvas = document.createElement('canvas');
|
||||
croppedCanvas.width = width * scaleX;
|
||||
croppedCanvas.height = height * scaleY;
|
||||
const croppedCtx = croppedCanvas.getContext('2d');
|
||||
|
||||
// Draw cropped section from full canvas
|
||||
croppedCtx.drawImage(
|
||||
fullCanvas,
|
||||
x * scaleX,
|
||||
y * scaleY,
|
||||
width * scaleX,
|
||||
height * scaleY,
|
||||
0,
|
||||
0,
|
||||
width * scaleX,
|
||||
height * scaleY
|
||||
);
|
||||
|
||||
cleanup();
|
||||
resolve(croppedCanvas);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle escape key
|
||||
const handleKeydown = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
cleanup();
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
|
||||
function cleanup() {
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
overlay.remove();
|
||||
selectionCanvas.remove();
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', handleKeydown);
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(selectionCanvas);
|
||||
|
||||
console.log('Snipping tool active: Draw a rectangle to select area. Press ESC to cancel.');
|
||||
}
|
||||
|
||||
window.canvasToFile = async function(canvas, filename = null) {
|
||||
console.log('canvasToFile called');
|
||||
return new Promise((resolve) => {
|
||||
const name = filename || `screenshot-${Date.now()}.png`;
|
||||
canvas.toBlob((blob) => {
|
||||
const file = new File([blob], name, { type: 'image/png' });
|
||||
resolve(file);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
console.log('✓ Screen Capture Tool loaded successfully');
|
||||
console.log('Functions available: window.captureScreenshot, window.captureSnip, window.canvasToFile');
|
||||
})();
|
||||
Reference in New Issue
Block a user