JakeFake222's picture
Update index.html
9bb556d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Images to PDF</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 50px;
text-align: center;
touch-action: none; /* Prevent default touch behaviors like scrolling */
}
#imageContainer {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
margin: 20px 0;
padding: 10px;
border: 1px solid #ccc;
}
.imageWrapper {
max-width: 200px;
cursor: move; /* For desktop */
position: relative;
user-select: none; /* Prevent text selection during drag/touch */
}
.imageWrapper img {
max-width: 100%;
height: auto;
border: 1px solid #ddd;
border-radius: 5px;
}
.imageWrapper.dragging {
opacity: 0.5; /* Visual feedback during drag/touch */
}
.imageWrapper.over {
border: 2px dashed #4CAF50; /* Visual feedback for drop target */
}
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<h1>Images to PDF Converter</h1>
<input type="file" id="imageInput" accept="image/*" multiple>
<p>Drag and drop (desktop) or tap and move (mobile) images to reorder them for the PDF.</p>
<div id="imageContainer"></div>
<button onclick="generatePDF()">Download as PDF</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script>
const { jsPDF } = window.jspdf;
const imageInput = document.getElementById('imageInput');
const imageContainer = document.getElementById('imageContainer');
let images = [];
// Handle image uploads
imageInput.addEventListener('change', (event) => {
images = [];
imageContainer.innerHTML = '';
const files = Array.from(event.target.files);
files.forEach((file) => {
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.src = e.target.result;
img.onload = () => {
images.push({ src: e.target.result, width: img.width, height: img.height });
renderImages();
};
};
reader.readAsDataURL(file);
});
});
// Render images with drag-and-drop and touch functionality
function renderImages() {
imageContainer.innerHTML = '';
images.forEach((image, index) => {
const wrapper = document.createElement('div');
wrapper.className = 'imageWrapper';
wrapper.draggable = true;
wrapper.dataset.index = index;
const img = new Image();
img.src = image.src;
wrapper.appendChild(img);
// Desktop drag-and-drop
wrapper.addEventListener('dragstart', (e) => {
wrapper.classList.add('dragging');
e.dataTransfer.setData('text/plain', index);
});
wrapper.addEventListener('dragend', () => {
wrapper.classList.remove('dragging');
clearOverStyles();
});
wrapper.addEventListener('dragover', (e) => {
e.preventDefault();
wrapper.classList.add('over');
});
wrapper.addEventListener('dragleave', () => {
wrapper.classList.remove('over');
});
wrapper.addEventListener('drop', (e) => {
e.preventDefault();
const draggedIndex = parseInt(e.dataTransfer.getData('text/plain'));
const dropIndex = parseInt(wrapper.dataset.index);
reorderImages(draggedIndex, dropIndex);
renderImages();
});
// Touch events for mobile
wrapper.addEventListener('touchstart', (e) => {
e.preventDefault();
wrapper.classList.add('dragging');
startTouchReorder(e, wrapper, index);
});
wrapper.addEventListener('touchmove', (e) => {
e.preventDefault();
handleTouchMove(e, wrapper);
});
wrapper.addEventListener('touchend', (e) => {
e.preventDefault();
wrapper.classList.remove('dragging');
endTouchReorder(wrapper, index);
clearOverStyles();
});
imageContainer.appendChild(wrapper);
});
}
// Touch reordering logic
let touchStartY = 0;
let targetIndex = null;
function startTouchReorder(event, wrapper, index) {
const touch = event.touches[0];
touchStartY = touch.clientY;
targetIndex = index;
}
function handleTouchMove(event, wrapper) {
const touch = event.touches[0];
const touchY = touch.clientY;
// Find the element under the touch point
const elements = document.elementsFromPoint(touch.clientX, touchY);
const targetWrapper = elements.find(el => el.classList.contains('imageWrapper') && el !== wrapper);
// Clear previous 'over' styles
clearOverStyles();
if (targetWrapper) {
targetWrapper.classList.add('over');
}
}
function endTouchReorder(wrapper, startIndex) {
const overElement = document.querySelector('.imageWrapper.over');
if (overElement) {
const dropIndex = parseInt(overElement.dataset.index);
reorderImages(startIndex, dropIndex);
renderImages();
}
}
function clearOverStyles() {
document.querySelectorAll('.imageWrapper.over').forEach(el => el.classList.remove('over'));
}
function reorderImages(draggedIndex, dropIndex) {
if (draggedIndex !== dropIndex) {
const [draggedImage] = images.splice(draggedIndex, 1);
images.splice(dropIndex, 0, draggedImage);
}
}
// Generate PDF from images
function generatePDF() {
if (images.length === 0) {
alert('Please upload at least one image.');
return;
}
const doc = new jsPDF();
const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();
const margin = 10;
const maxImgWidth = pageWidth - 2 * margin;
const maxImgHeight = pageHeight - 2 * margin;
images.forEach((image, index) => {
if (index > 0) {
doc.addPage();
}
// Calculate scaling to fit image within page
let imgWidth = image.width;
let imgHeight = image.height;
const ratio = Math.min(maxImgWidth / imgWidth, maxImgHeight / imgHeight);
imgWidth = imgWidth * ratio;
imgHeight = imgHeight * ratio;
// Center the image on the page
const x = (pageWidth - imgWidth) / 2;
const y = (pageHeight - imgHeight) / 2;
doc.addImage(image.src, 'JPEG', x, y, imgWidth, imgHeight);
});
doc.save('images.pdf');
}
</script>
</body>
</html>