- Modifikasi ukuran canvas agar sesuai dengan rasio video (portrait/landscape). - Tambahkan logika untuk menampilkan kontrol editor dan menyembunyikan kontrol kamera. - Sesuaikan ulang ukuran canvas menggambar agar sinkron dengan ukuran canvas utama. - Hapus elemen gambar pratinjau yang tidak lagi digunakan di komponen foto.
761 lines
29 KiB
PHP
761 lines
29 KiB
PHP
@push('scripts')
|
||
<script>
|
||
|
||
|
||
|
||
const style = document.createElement('style');
|
||
style.textContent = `
|
||
.draggable-text {
|
||
z-index: 1000;
|
||
}
|
||
.draggable-text:hover {
|
||
outline: 1px dashed #666;
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
|
||
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const editor = new UniversalCameraEditor();
|
||
const cameraButtons = document.querySelectorAll('#btnCamera');
|
||
const modal = document.getElementById('cameraModal');
|
||
const closeModal = document.getElementById('closeModal');
|
||
|
||
// Current input field to update
|
||
let currentInputField = null;
|
||
|
||
// Handle camera button click
|
||
cameraButtons.forEach(button => {
|
||
button.addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
const inputContainer = this.closest('.input-group');
|
||
currentInputField = inputContainer.querySelector('input[type="file"]');
|
||
modal.classList.remove('hidden');
|
||
modal.classList.add('modal-open');
|
||
editor.startCamera();
|
||
});
|
||
});
|
||
|
||
closeModal.addEventListener('click', function() {
|
||
modal.classList.add('hidden');
|
||
editor.closeCamera();
|
||
});
|
||
// Override save function
|
||
editor.saveAndUpload = async function() {
|
||
try {
|
||
// Create final canvas
|
||
const finalCanvas = document.createElement('canvas');
|
||
finalCanvas.width = this.canvas.width;
|
||
finalCanvas.height = this.canvas.height;
|
||
const ctx = finalCanvas.getContext('2d');
|
||
|
||
// Draw original photo and edited result on final canvas
|
||
ctx.drawImage(this.canvas, 0, 0);
|
||
ctx.drawImage(this.drawingCanvas, 0, 0);
|
||
|
||
// Convert canvas to Blob and create file
|
||
finalCanvas.toBlob(async (blob) => {
|
||
const file = new File([blob], `camera_photo_${Date.now()}.jpg`, {
|
||
type: "image/jpeg"
|
||
});
|
||
|
||
// Create FileList and update input field
|
||
const dataTransfer = new DataTransfer();
|
||
dataTransfer.items.add(file);
|
||
|
||
if (currentInputField) {
|
||
currentInputField.files = dataTransfer.files;
|
||
|
||
const event = new Event('change', {
|
||
bubbles: true
|
||
});
|
||
currentInputField.dispatchEvent(event);
|
||
const previewContainer = currentInputField.closest('.input-group')
|
||
.querySelector('.preview-container');
|
||
if (previewContainer) {
|
||
const img = document.createElement('img');
|
||
img.src = URL.createObjectURL(file);
|
||
img.className = 'w-full h-32 object-cover rounded-lg';
|
||
previewContainer.innerHTML = '';
|
||
previewContainer.appendChild(img);
|
||
}
|
||
}
|
||
|
||
// Close modal
|
||
|
||
modal.classList.remove('show');
|
||
modal.style.display = 'none';
|
||
modal.setAttribute('aria-hidden', 'true');
|
||
// document.body.classList.remove('modal-open');
|
||
|
||
|
||
// Remove modal backdrop if exists
|
||
const backdrop = document.querySelector('.modal-backdrop');
|
||
if (backdrop) {
|
||
backdrop.remove();
|
||
}
|
||
|
||
// Stop camera stream
|
||
if (editor.stream) {
|
||
editor.stream.getTracks().forEach(track => track.stop());
|
||
editor.stream = null;
|
||
}
|
||
|
||
// Reset camera to initial state
|
||
editor.closeCamera();
|
||
|
||
// Reset scroll if needed
|
||
window.scrollTo(0, 0); // Adjust as necessary
|
||
}, 'image/jpeg', 0.8);
|
||
|
||
} catch (error) {
|
||
console.error('Error saving photo:', error);
|
||
alert('Error saving photo. Please try again.');
|
||
}
|
||
};
|
||
|
||
|
||
// Handle escape key
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
const modal = document.getElementById('cameraModal');
|
||
if (modal.classList.contains('modal-open')) {
|
||
modal.classList.remove('modal-open');
|
||
modal.classList.add('hidden');
|
||
if (editor.stream) {
|
||
editor.stream.getTracks().forEach(track => track.stop());
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
|
||
|
||
|
||
});
|
||
</script>
|
||
|
||
<script>
|
||
class UniversalCameraEditor {
|
||
constructor() {
|
||
// Initialize elements
|
||
this.video = document.getElementById('video');
|
||
this.canvas = document.getElementById('canvas');
|
||
this.drawingCanvas = document.getElementById('drawingCanvas');
|
||
this.ctx = this.drawingCanvas.getContext('2d');
|
||
|
||
// Buttons
|
||
this.startButton = document.getElementById('startButton');
|
||
this.takePhotoButton = document.getElementById('takePhotoButton');
|
||
this.switchButton = document.getElementById('switchButton');
|
||
this.backButton = document.getElementById('backButton');
|
||
this.saveButton = document.getElementById('saveButton');
|
||
this.undoButton = document.getElementById('undoButton');
|
||
this.resetButton = document.getElementById('resetButton');
|
||
|
||
// Drawing controls
|
||
this.colorPicker = document.getElementById('colorPicker');
|
||
this.brushSize = document.getElementById('brushSize');
|
||
this.brushSizeValue = document.getElementById('brushSizeValue');
|
||
|
||
// Text modal elements
|
||
this.textModal = document.getElementById('textModal');
|
||
this.textInput = document.getElementById('textInput');
|
||
this.confirmTextBtn = document.getElementById('confirmTextBtn');
|
||
this.cancelTextBtn = document.getElementById('cancelTextBtn');
|
||
|
||
// Initialize state
|
||
this.stream = null;
|
||
this.currentFacingMode = 'environment';
|
||
this.isDrawing = false;
|
||
this.currentTool = 'brush';
|
||
this.drawingHistory = [];
|
||
this.historyIndex = -1;
|
||
|
||
// Drawing coordinates
|
||
this.startX = 0;
|
||
this.startY = 0;
|
||
this.lastX = 0;
|
||
this.lastY = 0;
|
||
|
||
// Setup
|
||
this.setupCanvas();
|
||
this.setupEventListeners();
|
||
this.setupDrawingContext();
|
||
|
||
|
||
// Add text overlay container
|
||
this.textOverlay = document.getElementById('textOverlay');
|
||
this.activeTextElement = null;
|
||
this.isDraggingText = false;
|
||
this.textOffset = {
|
||
x: 0,
|
||
y: 0
|
||
};
|
||
|
||
|
||
// Current input field reference
|
||
this.currentInputField = null;
|
||
|
||
}
|
||
|
||
setupCanvas() {
|
||
// Set initial canvas size
|
||
this.canvas.width = 1280;
|
||
this.canvas.height = (this.canvas.width * 3) / 4;
|
||
this.drawingCanvas.width = this.canvas.width;
|
||
this.drawingCanvas.height = this.canvas.height;
|
||
}
|
||
|
||
setupDrawingContext() {
|
||
this.ctx.strokeStyle = this.colorPicker.value;
|
||
this.ctx.lineWidth = this.brushSize.value;
|
||
this.ctx.lineCap = 'round';
|
||
this.ctx.lineJoin = 'round';
|
||
}
|
||
|
||
async startCamera() {
|
||
try {
|
||
if (this.stream) {
|
||
this.stream.getTracks().forEach(track => track.stop());
|
||
}
|
||
|
||
const constraints = {
|
||
video: {
|
||
facingMode: this.currentFacingMode,
|
||
width: {
|
||
ideal: 1280
|
||
},
|
||
height: {
|
||
ideal: 960
|
||
}
|
||
},
|
||
audio: false
|
||
};
|
||
|
||
this.stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||
this.video.srcObject = this.stream;
|
||
|
||
// Enable buttons after camera starts
|
||
this.takePhotoButton.disabled = false;
|
||
this.switchButton.disabled = false;
|
||
|
||
// Show video, hide canvas
|
||
this.video.style.display = 'block';
|
||
this.canvas.style.display = 'none';
|
||
this.drawingCanvas.style.display = 'none';
|
||
|
||
// Hide editor controls
|
||
document.getElementById('editorControls').classList.add('hidden');
|
||
document.getElementById('cameraControls').classList.remove('hidden');
|
||
|
||
} catch (error) {
|
||
console.error('Error accessing camera:', error);
|
||
alert('Error accessing camera. Please make sure you have granted camera permissions.');
|
||
}
|
||
}
|
||
|
||
takePhoto() {
|
||
// Draw video frame to canvas
|
||
const context = this.canvas.getContext('2d');
|
||
context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height);
|
||
|
||
// Hide video, show canvases
|
||
this.video.style.display = 'none';
|
||
this.canvas.style.display = 'block';
|
||
this.drawingCanvas.style.display = 'block';
|
||
|
||
// Show editor controls, hide camera controls
|
||
document.getElementById('editorControls').classList.remove('hidden');
|
||
document.getElementById('cameraControls').classList.add('hidden');
|
||
|
||
// Clear drawing history
|
||
this.drawingHistory = [];
|
||
this.historyIndex = -1;
|
||
this.saveDrawingState();
|
||
}
|
||
|
||
takePhoto() {
|
||
const context = this.canvas.getContext('2d');
|
||
|
||
// Determine if the video is in portrait or landscape mode
|
||
const isPortrait = this.video.videoHeight > this.video.videoWidth;
|
||
|
||
if (isPortrait) {
|
||
// Portrait mode
|
||
this.canvas.width = this.video.videoWidth;
|
||
this.canvas.height = this.video.videoHeight;
|
||
context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height);
|
||
} else {
|
||
// Landscape mode
|
||
this.canvas.width = 1280;
|
||
this.canvas.height = (this.canvas.width * this.video.videoHeight) / this.video.videoWidth;
|
||
context.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height);
|
||
}
|
||
|
||
// Adjust drawing canvas to match main canvas
|
||
this.drawingCanvas.width = this.canvas.width;
|
||
this.drawingCanvas.height = this.canvas.height;
|
||
|
||
// Hide video, show canvases
|
||
this.video.style.display = 'none';
|
||
this.canvas.style.display = 'block';
|
||
this.drawingCanvas.style.display = 'block';
|
||
|
||
// Show editor controls, hide camera controls
|
||
document.getElementById('editorControls').classList.remove('hidden');
|
||
document.getElementById('cameraControls').classList.add('hidden');
|
||
|
||
// Clear drawing history
|
||
this.drawingHistory = [];
|
||
this.historyIndex = -1;
|
||
this.saveDrawingState();
|
||
}
|
||
|
||
switchCamera() {
|
||
this.currentFacingMode = this.currentFacingMode === 'environment' ? 'user' : 'environment';
|
||
this.startCamera();
|
||
}
|
||
|
||
resetToCamera() {
|
||
// Clear canvases
|
||
const context = this.canvas.getContext('2d');
|
||
context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
|
||
// Reset history
|
||
this.drawingHistory = [];
|
||
this.historyIndex = -1;
|
||
|
||
// Restart camera
|
||
this.startCamera();
|
||
}
|
||
|
||
saveDrawingState() {
|
||
// Trim history if we're not at the end
|
||
if (this.historyIndex < this.drawingHistory.length - 1) {
|
||
this.drawingHistory = this.drawingHistory.slice(0, this.historyIndex + 1);
|
||
}
|
||
|
||
// Save current state
|
||
this.drawingHistory.push(this.drawingCanvas.toDataURL());
|
||
this.historyIndex++;
|
||
}
|
||
|
||
undo() {
|
||
if (this.historyIndex > 0) {
|
||
this.historyIndex--;
|
||
this.redrawHistory();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
resetDrawing() {
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
this.saveDrawingState();
|
||
}
|
||
|
||
// Implement all event listeners from previous code here
|
||
setupEventListeners() {
|
||
// Camera controls
|
||
this.startButton.onclick = () => this.startCamera();
|
||
this.takePhotoButton.onclick = () => this.takePhoto();
|
||
this.switchButton.onclick = () => this.switchCamera();
|
||
this.backButton.onclick = () => this.resetToCamera();
|
||
|
||
// Drawing controls
|
||
this.setupDrawingEvents();
|
||
this.setupToolButtons();
|
||
|
||
// Settings changes
|
||
this.colorPicker.oninput = (e) => this.ctx.strokeStyle = e.target.value;
|
||
this.brushSize.oninput = (e) => {
|
||
this.ctx.lineWidth = e.target.value;
|
||
this.brushSizeValue.textContent = `${e.target.value}px`;
|
||
};
|
||
|
||
// History controls
|
||
this.undoButton.onclick = () => this.undo();
|
||
this.resetButton.onclick = () => this.resetDrawing();
|
||
|
||
// Save functionality
|
||
this.saveButton.onclick = () => this.saveAndUpload();
|
||
|
||
|
||
// Text tool modal controls
|
||
this.confirmTextBtn.onclick = () => {
|
||
const text = this.textInput.value.trim();
|
||
if (text) {
|
||
this.addDraggableText(text);
|
||
this.textInput.value = '';
|
||
|
||
}
|
||
};
|
||
}
|
||
|
||
setupToolButtons() {
|
||
const toolButtons = document.querySelectorAll('.tool-btn');
|
||
toolButtons.forEach(button => {
|
||
button.onclick = () => {
|
||
toolButtons.forEach(btn => btn.classList.remove('active'));
|
||
button.classList.add('active');
|
||
this.currentTool = button.dataset.tool;
|
||
};
|
||
});
|
||
}
|
||
|
||
// Implement drawing events from previous code here
|
||
setupDrawingEvents() {
|
||
// Mouse events
|
||
this.drawingCanvas.addEventListener('mousedown', (e) => this.startDrawing(e));
|
||
this.drawingCanvas.addEventListener('mousemove', (e) => this.draw(e));
|
||
this.drawingCanvas.addEventListener('mouseup', () => this.stopDrawing());
|
||
this.drawingCanvas.addEventListener('mouseout', () => this.stopDrawing());
|
||
|
||
// Touch events
|
||
this.drawingCanvas.addEventListener('touchstart', (e) => {
|
||
if (this.shouldPreventDefault(e)) {
|
||
e.preventDefault();
|
||
}
|
||
const touch = e.touches[0];
|
||
const mouseEvent = new MouseEvent('mousedown', {
|
||
clientX: touch.clientX,
|
||
clientY: touch.clientY
|
||
});
|
||
this.startDrawing(mouseEvent);
|
||
}, {
|
||
passive: false
|
||
});
|
||
|
||
this.drawingCanvas.addEventListener('touchmove', (e) => {
|
||
if (this.shouldPreventDefault(e)) {
|
||
e.preventDefault();
|
||
}
|
||
const touch = e.touches[0];
|
||
const mouseEvent = new MouseEvent('mousemove', {
|
||
clientX: touch.clientX,
|
||
clientY: touch.clientY
|
||
});
|
||
this.draw(mouseEvent);
|
||
}, {
|
||
passive: false
|
||
});
|
||
|
||
this.drawingCanvas.addEventListener('touchend', () => {
|
||
this.stopDrawing();
|
||
}, {
|
||
passive: true
|
||
});
|
||
}
|
||
|
||
// Implement drawing methods from previous code here
|
||
startDrawing(e) {
|
||
this.isDrawing = true;
|
||
const rect = this.drawingCanvas.getBoundingClientRect();
|
||
const scaleX = this.drawingCanvas.width / rect.width;
|
||
const scaleY = this.drawingCanvas.height / rect.height;
|
||
|
||
this.startX = (e.clientX - rect.left) * scaleX;
|
||
this.startY = (e.clientY - rect.top) * scaleY;
|
||
this.lastX = this.startX;
|
||
this.lastY = this.startY;
|
||
|
||
if (this.currentTool === 'brush') {
|
||
this.ctx.beginPath();
|
||
this.ctx.moveTo(this.startX, this.startY);
|
||
}
|
||
}
|
||
|
||
addDraggableText(text) {
|
||
const textElement = document.createElement('div');
|
||
textElement.className = 'draggable-text';
|
||
textElement.style.cssText = `
|
||
position: absolute;
|
||
cursor: move;
|
||
user-select: none;
|
||
color: ${this.colorPicker.value};
|
||
font-size: ${this.brushSize.value * 2}px;
|
||
padding: 5px;
|
||
border-radius: 3px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
`;
|
||
|
||
// Create text span
|
||
const textSpan = document.createElement('span');
|
||
textSpan.textContent = text;
|
||
textElement.appendChild(textSpan);
|
||
|
||
// Create delete button
|
||
const deleteBtn = document.createElement('button');
|
||
deleteBtn.innerHTML = '×';
|
||
deleteBtn.style.cssText = `
|
||
border: none;
|
||
background: none;
|
||
color: #ff4444;
|
||
font-size: 20px;
|
||
cursor: pointer;
|
||
padding: 0;
|
||
line-height: 1;
|
||
opacity: 0;
|
||
transition: opacity 0.2s;
|
||
`;
|
||
textElement.appendChild(deleteBtn);
|
||
|
||
// Show/hide delete button on hover
|
||
textElement.addEventListener('mouseenter', () => {
|
||
deleteBtn.style.opacity = '1';
|
||
});
|
||
textElement.addEventListener('mouseleave', () => {
|
||
deleteBtn.style.opacity = '0';
|
||
});
|
||
|
||
// Delete functionality
|
||
deleteBtn.addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
textElement.remove();
|
||
this.saveDrawingState();
|
||
});
|
||
|
||
// Center the text initially
|
||
textElement.style.left = '50%';
|
||
textElement.style.top = '50%';
|
||
textElement.style.transform = 'translate(-50%, -50%)';
|
||
|
||
// Add drag functionality
|
||
this.setupDraggableText(textElement);
|
||
|
||
this.textOverlay.appendChild(textElement);
|
||
this.saveDrawingState();
|
||
}
|
||
|
||
setupDraggableText(element) {
|
||
let isDragging = false;
|
||
let currentX;
|
||
let currentY;
|
||
let initialX;
|
||
let initialY;
|
||
let xOffset = 0;
|
||
let yOffset = 0;
|
||
|
||
const dragStart = (e) => {
|
||
if (this.currentTool === 'text') {
|
||
const event = e.type === 'mousedown' ? e : e.touches[0];
|
||
initialX = event.clientX - xOffset;
|
||
initialY = event.clientY - yOffset;
|
||
|
||
if (e.target === element || e.target.parentNode === element) {
|
||
isDragging = true;
|
||
}
|
||
}
|
||
};
|
||
|
||
const drag = (e) => {
|
||
if (isDragging) {
|
||
e.preventDefault();
|
||
const event = e.type === 'mousemove' ? e : e.touches[0];
|
||
|
||
currentX = event.clientX - initialX;
|
||
currentY = event.clientY - initialY;
|
||
|
||
xOffset = currentX;
|
||
yOffset = currentY;
|
||
|
||
setTranslate(currentX, currentY, element);
|
||
}
|
||
};
|
||
|
||
const dragEnd = () => {
|
||
if (isDragging) {
|
||
isDragging = false;
|
||
this.saveDrawingState();
|
||
}
|
||
};
|
||
|
||
const setTranslate = (xPos, yPos, el) => {
|
||
el.style.transform = `translate(${xPos}px, ${yPos}px)`;
|
||
};
|
||
|
||
// Mouse events
|
||
element.addEventListener('mousedown', dragStart);
|
||
document.addEventListener('mousemove', drag);
|
||
document.addEventListener('mouseup', dragEnd);
|
||
|
||
// Touch events
|
||
element.addEventListener('touchstart', dragStart);
|
||
document.addEventListener('touchmove', drag);
|
||
document.addEventListener('touchend', dragEnd);
|
||
}
|
||
|
||
// Add this CSS to your stylesheet
|
||
|
||
|
||
draw(e) {
|
||
if (!this.isDrawing) return;
|
||
|
||
const rect = this.drawingCanvas.getBoundingClientRect();
|
||
const scaleX = this.drawingCanvas.width / rect.width;
|
||
const scaleY = this.drawingCanvas.height / rect.height;
|
||
const x = (e.clientX - rect.left) * scaleX;
|
||
const y = (e.clientY - rect.top) * scaleY;
|
||
|
||
switch (this.currentTool) {
|
||
case 'arrow':
|
||
// Restore the previous state before drawing new arrow
|
||
if (this.historyIndex >= 0) {
|
||
this.redrawHistory();
|
||
} else {
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
}
|
||
this.drawArrow(this.startX, this.startY, x, y);
|
||
break;
|
||
|
||
case 'brush':
|
||
this.ctx.lineTo(x, y);
|
||
this.ctx.stroke();
|
||
break;
|
||
|
||
case 'rectangle':
|
||
// Restore the previous state before drawing new rectangle
|
||
if (this.historyIndex >= 0) {
|
||
this.redrawHistory();
|
||
} else {
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
}
|
||
this.ctx.beginPath();
|
||
this.ctx.strokeRect(this.startX, this.startY, x - this.startX, y - this.startY);
|
||
break;
|
||
|
||
case 'circle':
|
||
// Restore the previous state before drawing new circle
|
||
if (this.historyIndex >= 0) {
|
||
this.redrawHistory();
|
||
} else {
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
}
|
||
const radius = Math.sqrt(Math.pow(x - this.startX, 2) + Math.pow(y - this.startY, 2));
|
||
this.ctx.beginPath();
|
||
this.ctx.arc(this.startX, this.startY, radius, 0, Math.PI * 2);
|
||
this.ctx.stroke();
|
||
break;
|
||
}
|
||
|
||
this.lastX = x;
|
||
this.lastY = y;
|
||
}
|
||
|
||
drawArrow(fromX, fromY, toX, toY) {
|
||
const headLength = 20;
|
||
const headAngle = Math.PI / 6;
|
||
|
||
// Calculate angle
|
||
const angle = Math.atan2(toY - fromY, toX - fromX);
|
||
|
||
// Draw main line
|
||
this.ctx.beginPath();
|
||
this.ctx.moveTo(fromX, fromY);
|
||
this.ctx.lineTo(toX, toY);
|
||
this.ctx.stroke();
|
||
|
||
// Draw arrowhead
|
||
this.ctx.beginPath();
|
||
this.ctx.moveTo(toX, toY);
|
||
this.ctx.lineTo(
|
||
toX - headLength * Math.cos(angle - headAngle),
|
||
toY - headLength * Math.sin(angle - headAngle)
|
||
);
|
||
this.ctx.moveTo(toX, toY);
|
||
this.ctx.lineTo(
|
||
toX - headLength * Math.cos(angle + headAngle),
|
||
toY - headLength * Math.sin(angle + headAngle)
|
||
);
|
||
this.ctx.stroke();
|
||
}
|
||
|
||
startDrawing(e) {
|
||
this.isDrawing = true;
|
||
const rect = this.drawingCanvas.getBoundingClientRect();
|
||
const scaleX = this.drawingCanvas.width / rect.width;
|
||
const scaleY = this.drawingCanvas.height / rect.height;
|
||
|
||
this.startX = (e.clientX - rect.left) * scaleX;
|
||
this.startY = (e.clientY - rect.top) * scaleY;
|
||
this.lastX = this.startX;
|
||
this.lastY = this.startY;
|
||
|
||
if (this.currentTool === 'brush') {
|
||
this.ctx.beginPath();
|
||
this.ctx.moveTo(this.startX, this.startY);
|
||
}
|
||
}
|
||
|
||
stopDrawing() {
|
||
if (this.isDrawing) {
|
||
this.isDrawing = false;
|
||
if (this.currentTool === 'brush') {
|
||
this.ctx.closePath();
|
||
}
|
||
this.saveDrawingState();
|
||
}
|
||
}
|
||
|
||
redrawHistory() {
|
||
if (this.historyIndex >= 0 && this.drawingHistory[this.historyIndex]) {
|
||
const img = new Image();
|
||
img.src = this.drawingHistory[this.historyIndex];
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
this.ctx.drawImage(img, 0, 0);
|
||
} else {
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
}
|
||
}
|
||
closeEditor() {
|
||
if (this.stream) {
|
||
this.stream.getTracks().forEach(track => track.stop());
|
||
}
|
||
|
||
// Clear canvases and text overlay
|
||
this.ctx.clearRect(0, 0, this.drawingCanvas.width, this.drawingCanvas.height);
|
||
const mainCtx = this.canvas.getContext('2d');
|
||
mainCtx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||
this.textOverlay.innerHTML = '';
|
||
|
||
// Reset state
|
||
this.drawingHistory = [];
|
||
this.historyIndex = -1;
|
||
this.currentInputField = null;
|
||
|
||
// Close modals
|
||
this.cameraModal.hide();
|
||
this.textInputModal.hide();
|
||
}
|
||
|
||
// Override this method in your implementation
|
||
saveAndUpload() {
|
||
|
||
}
|
||
|
||
closeCamera() {
|
||
// Stop the video stream
|
||
if (this.stream) {
|
||
this.stream.getTracks().forEach(track => track.stop());
|
||
}
|
||
|
||
// Hide video and canvas elements
|
||
this.video.style.display = 'none';
|
||
this.canvas.style.display = 'none';
|
||
this.drawingCanvas.style.display = 'none';
|
||
|
||
|
||
// Reset any additional state if needed
|
||
this.stream = null;
|
||
}
|
||
|
||
}
|
||
</script>
|
||
@endpush
|