CropTool-fix
This commit is contained in:
parent
5fb7d2b01b
commit
3642d5b875
4
dist/editor.html
vendored
4
dist/editor.html
vendored
@ -81,8 +81,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<button id="select-tool" class="tool-button" title="Select (V)">Select</button>
|
<!-- <button id="select-tool" class="tool-button" title="Select (V)">Select</button>
|
||||||
<button id="move-tool" class="tool-button" title="Move (M)">Move</button>
|
<button id="move-tool" class="tool-button" title="Move (M)">Move</button> -->
|
||||||
<button id="pen-tool" class="tool-button" title="Pen (P)">Pen</button>
|
<button id="pen-tool" class="tool-button" title="Pen (P)">Pen</button>
|
||||||
<button id="rectangle-tool" class="tool-button" title="Rectangle (R)">Rectangle</button>
|
<button id="rectangle-tool" class="tool-button" title="Rectangle (R)">Rectangle</button>
|
||||||
<button id="arrow-tool" class="tool-button" title="Arrow (A)">Arrow</button>
|
<button id="arrow-tool" class="tool-button" title="Arrow (A)">Arrow</button>
|
||||||
|
121
dist/popup.js
vendored
121
dist/popup.js
vendored
@ -21,14 +21,13 @@ class ScreenshotEditor {
|
|||||||
this.lastY = 0;
|
this.lastY = 0;
|
||||||
this.undoStack = [];
|
this.undoStack = [];
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this.shapes = [];
|
|
||||||
this.selectedShape = null;
|
|
||||||
this.isDragging = false;
|
|
||||||
this.originalImage = null;
|
this.originalImage = null;
|
||||||
this.currentState = null;
|
this.currentState = null;
|
||||||
this.scale = 1;
|
this.scale = 1;
|
||||||
this.paths = [];
|
this.paths = [];
|
||||||
this.currentPath = [];
|
this.currentPath = [];
|
||||||
|
this.cropStart = null;
|
||||||
|
this.cropEnd = null;
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.setupTools();
|
this.setupTools();
|
||||||
console.log('ScreenshotEditor initialized');
|
console.log('ScreenshotEditor initialized');
|
||||||
@ -115,7 +114,7 @@ class ScreenshotEditor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
setupTools() {
|
setupTools() {
|
||||||
const tools = ['select', 'pen', 'rectangle', 'arrow', 'crop'];
|
const tools = ['pen', 'rectangle', 'arrow', 'crop'];
|
||||||
tools.forEach(tool => {
|
tools.forEach(tool => {
|
||||||
const button = document.getElementById(`${tool}-tool`);
|
const button = document.getElementById(`${tool}-tool`);
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -160,16 +159,23 @@ class ScreenshotEditor {
|
|||||||
this.isDrawing = true;
|
this.isDrawing = true;
|
||||||
|
|
||||||
// Calculate coordinates taking into account scale and DPR
|
// Calculate coordinates taking into account scale and DPR
|
||||||
this.startX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
const x = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
||||||
this.startY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
const y = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
||||||
this.lastX = this.startX;
|
this.startX = x;
|
||||||
this.lastY = this.startY;
|
this.startY = y;
|
||||||
if (this.drawingMode === 'pen') {
|
this.lastX = x;
|
||||||
// Start a new path array for the current drawing
|
this.lastY = y;
|
||||||
|
if (this.drawingMode === 'crop') {
|
||||||
|
this.cropStart = {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
};
|
||||||
|
this.cropEnd = null;
|
||||||
|
} else if (this.drawingMode === 'pen') {
|
||||||
this.currentPath = [];
|
this.currentPath = [];
|
||||||
this.currentPath.push({
|
this.currentPath.push({
|
||||||
x: this.startX,
|
x,
|
||||||
y: this.startY
|
y
|
||||||
});
|
});
|
||||||
this.paths.push(this.currentPath);
|
this.paths.push(this.currentPath);
|
||||||
}
|
}
|
||||||
@ -181,10 +187,6 @@ class ScreenshotEditor {
|
|||||||
const currentX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
const currentX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
||||||
const currentY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
const currentY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
||||||
|
|
||||||
// Get the current state as an image
|
|
||||||
const baseImage = new Image();
|
|
||||||
baseImage.src = this.currentState || this.canvas.toDataURL();
|
|
||||||
|
|
||||||
// Clear the canvas
|
// Clear the canvas
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
|
||||||
@ -204,13 +206,10 @@ class ScreenshotEditor {
|
|||||||
this.ctx.lineJoin = 'round';
|
this.ctx.lineJoin = 'round';
|
||||||
switch (this.drawingMode) {
|
switch (this.drawingMode) {
|
||||||
case 'pen':
|
case 'pen':
|
||||||
// Add point to current path
|
|
||||||
this.currentPath.push({
|
this.currentPath.push({
|
||||||
x: currentX,
|
x: currentX,
|
||||||
y: currentY
|
y: currentY
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw the entire current path
|
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y);
|
this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y);
|
||||||
for (let i = 1; i < this.currentPath.length; i++) {
|
for (let i = 1; i < this.currentPath.length; i++) {
|
||||||
@ -227,6 +226,29 @@ class ScreenshotEditor {
|
|||||||
case 'arrow':
|
case 'arrow':
|
||||||
this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY);
|
this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY);
|
||||||
break;
|
break;
|
||||||
|
case 'crop':
|
||||||
|
// Draw crop rectangle
|
||||||
|
this.ctx.save();
|
||||||
|
this.ctx.strokeStyle = '#ffffff';
|
||||||
|
this.ctx.lineWidth = 2;
|
||||||
|
this.ctx.setLineDash([5, 5]);
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY);
|
||||||
|
this.ctx.stroke();
|
||||||
|
|
||||||
|
// Draw semi-transparent overlay
|
||||||
|
this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
|
||||||
|
this.ctx.fillRect(0, 0, this.canvas.width, this.startY); // Top
|
||||||
|
this.ctx.fillRect(0, currentY, this.canvas.width, this.canvas.height - currentY); // Bottom
|
||||||
|
this.ctx.fillRect(0, this.startY, this.startX, currentY - this.startY); // Left
|
||||||
|
this.ctx.fillRect(currentX, this.startY, this.canvas.width - currentX, currentY - this.startY); // Right
|
||||||
|
|
||||||
|
this.ctx.restore();
|
||||||
|
this.cropEnd = {
|
||||||
|
x: currentX,
|
||||||
|
y: currentY
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawArrow(ctx, fromX, fromY, toX, toY) {
|
drawArrow(ctx, fromX, fromY, toX, toY) {
|
||||||
@ -248,14 +270,65 @@ class ScreenshotEditor {
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
stopDrawing() {
|
stopDrawing() {
|
||||||
if (this.isDrawing) {
|
if (!this.isDrawing) return;
|
||||||
this.isDrawing = false;
|
this.isDrawing = false;
|
||||||
// Save the current state with the completed drawing
|
if (this.drawingMode === 'crop' && this.cropStart && this.cropEnd) {
|
||||||
|
// Ensure positive width and height
|
||||||
|
const x = Math.min(this.cropStart.x, this.cropEnd.x);
|
||||||
|
const y = Math.min(this.cropStart.y, this.cropEnd.y);
|
||||||
|
const width = Math.abs(this.cropEnd.x - this.cropStart.x);
|
||||||
|
const height = Math.abs(this.cropEnd.y - this.cropStart.y);
|
||||||
|
|
||||||
|
// Create a temporary canvas for cropping
|
||||||
|
const tempCanvas = document.createElement('canvas');
|
||||||
|
const tempCtx = tempCanvas.getContext('2d');
|
||||||
|
tempCanvas.width = width;
|
||||||
|
tempCanvas.height = height;
|
||||||
|
|
||||||
|
// Draw the cropped portion
|
||||||
|
if (this.currentState) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
tempCtx.drawImage(img, -x, -y);
|
||||||
|
|
||||||
|
// Update canvas size
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
// Draw cropped image
|
||||||
|
this.ctx.drawImage(tempCanvas, 0, 0);
|
||||||
|
|
||||||
|
// Save the cropped state
|
||||||
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
|
this.saveState();
|
||||||
|
};
|
||||||
|
img.src = this.currentState;
|
||||||
|
} else if (this.originalImage) {
|
||||||
|
tempCtx.drawImage(this.originalImage, -x, -y);
|
||||||
|
|
||||||
|
// Update canvas size
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
// Draw cropped image
|
||||||
|
this.ctx.drawImage(tempCanvas, 0, 0);
|
||||||
|
|
||||||
|
// Save the cropped state
|
||||||
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
|
this.saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset crop points
|
||||||
|
this.cropStart = null;
|
||||||
|
this.cropEnd = null;
|
||||||
|
} else {
|
||||||
|
// For other tools, save the current state
|
||||||
this.currentState = this.canvas.toDataURL('image/png');
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
this.saveState();
|
this.saveState();
|
||||||
// Reset current path
|
|
||||||
this.currentPath = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset current path
|
||||||
|
this.currentPath = [];
|
||||||
}
|
}
|
||||||
undo() {
|
undo() {
|
||||||
if (this.undoStack.length > 1) {
|
if (this.undoStack.length > 1) {
|
||||||
|
121
dist/screenshot-editor.js
vendored
121
dist/screenshot-editor.js
vendored
@ -16,14 +16,13 @@ class ScreenshotEditor {
|
|||||||
this.lastY = 0;
|
this.lastY = 0;
|
||||||
this.undoStack = [];
|
this.undoStack = [];
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this.shapes = [];
|
|
||||||
this.selectedShape = null;
|
|
||||||
this.isDragging = false;
|
|
||||||
this.originalImage = null;
|
this.originalImage = null;
|
||||||
this.currentState = null;
|
this.currentState = null;
|
||||||
this.scale = 1;
|
this.scale = 1;
|
||||||
this.paths = [];
|
this.paths = [];
|
||||||
this.currentPath = [];
|
this.currentPath = [];
|
||||||
|
this.cropStart = null;
|
||||||
|
this.cropEnd = null;
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.setupTools();
|
this.setupTools();
|
||||||
console.log('ScreenshotEditor initialized');
|
console.log('ScreenshotEditor initialized');
|
||||||
@ -110,7 +109,7 @@ class ScreenshotEditor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
setupTools() {
|
setupTools() {
|
||||||
const tools = ['select', 'pen', 'rectangle', 'arrow', 'crop'];
|
const tools = ['pen', 'rectangle', 'arrow', 'crop'];
|
||||||
tools.forEach(tool => {
|
tools.forEach(tool => {
|
||||||
const button = document.getElementById(`${tool}-tool`);
|
const button = document.getElementById(`${tool}-tool`);
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -155,16 +154,23 @@ class ScreenshotEditor {
|
|||||||
this.isDrawing = true;
|
this.isDrawing = true;
|
||||||
|
|
||||||
// Calculate coordinates taking into account scale and DPR
|
// Calculate coordinates taking into account scale and DPR
|
||||||
this.startX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
const x = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
||||||
this.startY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
const y = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
||||||
this.lastX = this.startX;
|
this.startX = x;
|
||||||
this.lastY = this.startY;
|
this.startY = y;
|
||||||
if (this.drawingMode === 'pen') {
|
this.lastX = x;
|
||||||
// Start a new path array for the current drawing
|
this.lastY = y;
|
||||||
|
if (this.drawingMode === 'crop') {
|
||||||
|
this.cropStart = {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
};
|
||||||
|
this.cropEnd = null;
|
||||||
|
} else if (this.drawingMode === 'pen') {
|
||||||
this.currentPath = [];
|
this.currentPath = [];
|
||||||
this.currentPath.push({
|
this.currentPath.push({
|
||||||
x: this.startX,
|
x,
|
||||||
y: this.startY
|
y
|
||||||
});
|
});
|
||||||
this.paths.push(this.currentPath);
|
this.paths.push(this.currentPath);
|
||||||
}
|
}
|
||||||
@ -176,10 +182,6 @@ class ScreenshotEditor {
|
|||||||
const currentX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
const currentX = (e.clientX - rect.left) / rect.width * this.canvas.width / dpr;
|
||||||
const currentY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
const currentY = (e.clientY - rect.top) / rect.height * this.canvas.height / dpr;
|
||||||
|
|
||||||
// Get the current state as an image
|
|
||||||
const baseImage = new Image();
|
|
||||||
baseImage.src = this.currentState || this.canvas.toDataURL();
|
|
||||||
|
|
||||||
// Clear the canvas
|
// Clear the canvas
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
|
||||||
@ -199,13 +201,10 @@ class ScreenshotEditor {
|
|||||||
this.ctx.lineJoin = 'round';
|
this.ctx.lineJoin = 'round';
|
||||||
switch (this.drawingMode) {
|
switch (this.drawingMode) {
|
||||||
case 'pen':
|
case 'pen':
|
||||||
// Add point to current path
|
|
||||||
this.currentPath.push({
|
this.currentPath.push({
|
||||||
x: currentX,
|
x: currentX,
|
||||||
y: currentY
|
y: currentY
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw the entire current path
|
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y);
|
this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y);
|
||||||
for (let i = 1; i < this.currentPath.length; i++) {
|
for (let i = 1; i < this.currentPath.length; i++) {
|
||||||
@ -222,6 +221,29 @@ class ScreenshotEditor {
|
|||||||
case 'arrow':
|
case 'arrow':
|
||||||
this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY);
|
this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY);
|
||||||
break;
|
break;
|
||||||
|
case 'crop':
|
||||||
|
// Draw crop rectangle
|
||||||
|
this.ctx.save();
|
||||||
|
this.ctx.strokeStyle = '#ffffff';
|
||||||
|
this.ctx.lineWidth = 2;
|
||||||
|
this.ctx.setLineDash([5, 5]);
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY);
|
||||||
|
this.ctx.stroke();
|
||||||
|
|
||||||
|
// Draw semi-transparent overlay
|
||||||
|
this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
|
||||||
|
this.ctx.fillRect(0, 0, this.canvas.width, this.startY); // Top
|
||||||
|
this.ctx.fillRect(0, currentY, this.canvas.width, this.canvas.height - currentY); // Bottom
|
||||||
|
this.ctx.fillRect(0, this.startY, this.startX, currentY - this.startY); // Left
|
||||||
|
this.ctx.fillRect(currentX, this.startY, this.canvas.width - currentX, currentY - this.startY); // Right
|
||||||
|
|
||||||
|
this.ctx.restore();
|
||||||
|
this.cropEnd = {
|
||||||
|
x: currentX,
|
||||||
|
y: currentY
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawArrow(ctx, fromX, fromY, toX, toY) {
|
drawArrow(ctx, fromX, fromY, toX, toY) {
|
||||||
@ -243,14 +265,65 @@ class ScreenshotEditor {
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
stopDrawing() {
|
stopDrawing() {
|
||||||
if (this.isDrawing) {
|
if (!this.isDrawing) return;
|
||||||
this.isDrawing = false;
|
this.isDrawing = false;
|
||||||
// Save the current state with the completed drawing
|
if (this.drawingMode === 'crop' && this.cropStart && this.cropEnd) {
|
||||||
|
// Ensure positive width and height
|
||||||
|
const x = Math.min(this.cropStart.x, this.cropEnd.x);
|
||||||
|
const y = Math.min(this.cropStart.y, this.cropEnd.y);
|
||||||
|
const width = Math.abs(this.cropEnd.x - this.cropStart.x);
|
||||||
|
const height = Math.abs(this.cropEnd.y - this.cropStart.y);
|
||||||
|
|
||||||
|
// Create a temporary canvas for cropping
|
||||||
|
const tempCanvas = document.createElement('canvas');
|
||||||
|
const tempCtx = tempCanvas.getContext('2d');
|
||||||
|
tempCanvas.width = width;
|
||||||
|
tempCanvas.height = height;
|
||||||
|
|
||||||
|
// Draw the cropped portion
|
||||||
|
if (this.currentState) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
tempCtx.drawImage(img, -x, -y);
|
||||||
|
|
||||||
|
// Update canvas size
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
// Draw cropped image
|
||||||
|
this.ctx.drawImage(tempCanvas, 0, 0);
|
||||||
|
|
||||||
|
// Save the cropped state
|
||||||
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
|
this.saveState();
|
||||||
|
};
|
||||||
|
img.src = this.currentState;
|
||||||
|
} else if (this.originalImage) {
|
||||||
|
tempCtx.drawImage(this.originalImage, -x, -y);
|
||||||
|
|
||||||
|
// Update canvas size
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
// Draw cropped image
|
||||||
|
this.ctx.drawImage(tempCanvas, 0, 0);
|
||||||
|
|
||||||
|
// Save the cropped state
|
||||||
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
|
this.saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset crop points
|
||||||
|
this.cropStart = null;
|
||||||
|
this.cropEnd = null;
|
||||||
|
} else {
|
||||||
|
// For other tools, save the current state
|
||||||
this.currentState = this.canvas.toDataURL('image/png');
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
this.saveState();
|
this.saveState();
|
||||||
// Reset current path
|
|
||||||
this.currentPath = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset current path
|
||||||
|
this.currentPath = [];
|
||||||
}
|
}
|
||||||
undo() {
|
undo() {
|
||||||
if (this.undoStack.length > 1) {
|
if (this.undoStack.length > 1) {
|
||||||
|
@ -81,8 +81,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<button id="select-tool" class="tool-button" title="Select (V)">Select</button>
|
<!-- <button id="select-tool" class="tool-button" title="Select (V)">Select</button>
|
||||||
<button id="move-tool" class="tool-button" title="Move (M)">Move</button>
|
<button id="move-tool" class="tool-button" title="Move (M)">Move</button> -->
|
||||||
<button id="pen-tool" class="tool-button" title="Pen (P)">Pen</button>
|
<button id="pen-tool" class="tool-button" title="Pen (P)">Pen</button>
|
||||||
<button id="rectangle-tool" class="tool-button" title="Rectangle (R)">Rectangle</button>
|
<button id="rectangle-tool" class="tool-button" title="Rectangle (R)">Rectangle</button>
|
||||||
<button id="arrow-tool" class="tool-button" title="Arrow (A)">Arrow</button>
|
<button id="arrow-tool" class="tool-button" title="Arrow (A)">Arrow</button>
|
||||||
|
@ -13,14 +13,13 @@ class ScreenshotEditor {
|
|||||||
this.lastY = 0;
|
this.lastY = 0;
|
||||||
this.undoStack = [];
|
this.undoStack = [];
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this.shapes = [];
|
|
||||||
this.selectedShape = null;
|
|
||||||
this.isDragging = false;
|
|
||||||
this.originalImage = null;
|
this.originalImage = null;
|
||||||
this.currentState = null;
|
this.currentState = null;
|
||||||
this.scale = 1;
|
this.scale = 1;
|
||||||
this.paths = [];
|
this.paths = [];
|
||||||
this.currentPath = [];
|
this.currentPath = [];
|
||||||
|
this.cropStart = null;
|
||||||
|
this.cropEnd = null;
|
||||||
|
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.setupTools();
|
this.setupTools();
|
||||||
@ -116,7 +115,7 @@ class ScreenshotEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupTools() {
|
setupTools() {
|
||||||
const tools = ['select', 'pen', 'rectangle', 'arrow', 'crop'];
|
const tools = ['pen', 'rectangle', 'arrow', 'crop'];
|
||||||
tools.forEach(tool => {
|
tools.forEach(tool => {
|
||||||
const button = document.getElementById(`${tool}-tool`);
|
const button = document.getElementById(`${tool}-tool`);
|
||||||
if (button) {
|
if (button) {
|
||||||
@ -161,15 +160,20 @@ class ScreenshotEditor {
|
|||||||
this.isDrawing = true;
|
this.isDrawing = true;
|
||||||
|
|
||||||
// Calculate coordinates taking into account scale and DPR
|
// Calculate coordinates taking into account scale and DPR
|
||||||
this.startX = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr;
|
const x = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr;
|
||||||
this.startY = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr;
|
const y = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr;
|
||||||
this.lastX = this.startX;
|
|
||||||
this.lastY = this.startY;
|
|
||||||
|
|
||||||
if (this.drawingMode === 'pen') {
|
this.startX = x;
|
||||||
// Start a new path array for the current drawing
|
this.startY = y;
|
||||||
|
this.lastX = x;
|
||||||
|
this.lastY = y;
|
||||||
|
|
||||||
|
if (this.drawingMode === 'crop') {
|
||||||
|
this.cropStart = { x, y };
|
||||||
|
this.cropEnd = null;
|
||||||
|
} else if (this.drawingMode === 'pen') {
|
||||||
this.currentPath = [];
|
this.currentPath = [];
|
||||||
this.currentPath.push({ x: this.startX, y: this.startY });
|
this.currentPath.push({ x, y });
|
||||||
this.paths.push(this.currentPath);
|
this.paths.push(this.currentPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,10 +186,6 @@ class ScreenshotEditor {
|
|||||||
const currentX = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr;
|
const currentX = ((e.clientX - rect.left) / rect.width) * this.canvas.width / dpr;
|
||||||
const currentY = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr;
|
const currentY = ((e.clientY - rect.top) / rect.height) * this.canvas.height / dpr;
|
||||||
|
|
||||||
// Get the current state as an image
|
|
||||||
const baseImage = new Image();
|
|
||||||
baseImage.src = this.currentState || this.canvas.toDataURL();
|
|
||||||
|
|
||||||
// Clear the canvas
|
// Clear the canvas
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
|
||||||
@ -206,10 +206,7 @@ class ScreenshotEditor {
|
|||||||
|
|
||||||
switch (this.drawingMode) {
|
switch (this.drawingMode) {
|
||||||
case 'pen':
|
case 'pen':
|
||||||
// Add point to current path
|
|
||||||
this.currentPath.push({ x: currentX, y: currentY });
|
this.currentPath.push({ x: currentX, y: currentY });
|
||||||
|
|
||||||
// Draw the entire current path
|
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y);
|
this.ctx.moveTo(this.currentPath[0].x, this.currentPath[0].y);
|
||||||
for (let i = 1; i < this.currentPath.length; i++) {
|
for (let i = 1; i < this.currentPath.length; i++) {
|
||||||
@ -221,18 +218,34 @@ class ScreenshotEditor {
|
|||||||
|
|
||||||
case 'rectangle':
|
case 'rectangle':
|
||||||
this.ctx.beginPath();
|
this.ctx.beginPath();
|
||||||
this.ctx.rect(
|
this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY);
|
||||||
this.startX,
|
|
||||||
this.startY,
|
|
||||||
currentX - this.startX,
|
|
||||||
currentY - this.startY
|
|
||||||
);
|
|
||||||
this.ctx.stroke();
|
this.ctx.stroke();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'arrow':
|
case 'arrow':
|
||||||
this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY);
|
this.drawArrow(this.ctx, this.startX, this.startY, currentX, currentY);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'crop':
|
||||||
|
// Draw crop rectangle
|
||||||
|
this.ctx.save();
|
||||||
|
this.ctx.strokeStyle = '#ffffff';
|
||||||
|
this.ctx.lineWidth = 2;
|
||||||
|
this.ctx.setLineDash([5, 5]);
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.rect(this.startX, this.startY, currentX - this.startX, currentY - this.startY);
|
||||||
|
this.ctx.stroke();
|
||||||
|
|
||||||
|
// Draw semi-transparent overlay
|
||||||
|
this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
|
||||||
|
this.ctx.fillRect(0, 0, this.canvas.width, this.startY); // Top
|
||||||
|
this.ctx.fillRect(0, currentY, this.canvas.width, this.canvas.height - currentY); // Bottom
|
||||||
|
this.ctx.fillRect(0, this.startY, this.startX, currentY - this.startY); // Left
|
||||||
|
this.ctx.fillRect(currentX, this.startY, this.canvas.width - currentX, currentY - this.startY); // Right
|
||||||
|
|
||||||
|
this.ctx.restore();
|
||||||
|
this.cropEnd = { x: currentX, y: currentY };
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,14 +275,66 @@ class ScreenshotEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stopDrawing() {
|
stopDrawing() {
|
||||||
if (this.isDrawing) {
|
if (!this.isDrawing) return;
|
||||||
this.isDrawing = false;
|
this.isDrawing = false;
|
||||||
// Save the current state with the completed drawing
|
|
||||||
|
if (this.drawingMode === 'crop' && this.cropStart && this.cropEnd) {
|
||||||
|
// Ensure positive width and height
|
||||||
|
const x = Math.min(this.cropStart.x, this.cropEnd.x);
|
||||||
|
const y = Math.min(this.cropStart.y, this.cropEnd.y);
|
||||||
|
const width = Math.abs(this.cropEnd.x - this.cropStart.x);
|
||||||
|
const height = Math.abs(this.cropEnd.y - this.cropStart.y);
|
||||||
|
|
||||||
|
// Create a temporary canvas for cropping
|
||||||
|
const tempCanvas = document.createElement('canvas');
|
||||||
|
const tempCtx = tempCanvas.getContext('2d');
|
||||||
|
tempCanvas.width = width;
|
||||||
|
tempCanvas.height = height;
|
||||||
|
|
||||||
|
// Draw the cropped portion
|
||||||
|
if (this.currentState) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
tempCtx.drawImage(img, -x, -y);
|
||||||
|
|
||||||
|
// Update canvas size
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
// Draw cropped image
|
||||||
|
this.ctx.drawImage(tempCanvas, 0, 0);
|
||||||
|
|
||||||
|
// Save the cropped state
|
||||||
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
|
this.saveState();
|
||||||
|
};
|
||||||
|
img.src = this.currentState;
|
||||||
|
} else if (this.originalImage) {
|
||||||
|
tempCtx.drawImage(this.originalImage, -x, -y);
|
||||||
|
|
||||||
|
// Update canvas size
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
// Draw cropped image
|
||||||
|
this.ctx.drawImage(tempCanvas, 0, 0);
|
||||||
|
|
||||||
|
// Save the cropped state
|
||||||
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
|
this.saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset crop points
|
||||||
|
this.cropStart = null;
|
||||||
|
this.cropEnd = null;
|
||||||
|
} else {
|
||||||
|
// For other tools, save the current state
|
||||||
this.currentState = this.canvas.toDataURL('image/png');
|
this.currentState = this.canvas.toDataURL('image/png');
|
||||||
this.saveState();
|
this.saveState();
|
||||||
// Reset current path
|
|
||||||
this.currentPath = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset current path
|
||||||
|
this.currentPath = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user