duplicate image on cmd+click

Hunter
Monday, October 20th, 2025 at 12:32 PM

script.js+63-1

script.js
185  	grid.appendChild(container);
186  
187  	setupImageHandlers(imageData);
188 +
189 +	return imageData;
190  }
191  
192  function calculatePanBounds(imageData) {

261  		bringToFront(container);
262  	});
263  
    -	// Moving / Deleting
264 +	// Moving / Deleting / Duplicating
265  	container.addEventListener('mousedown', (e) => {
266  		if (e.target.classList.contains('resize-handle')) return;
267  

277  			return;
278  		}
279  
280 +		// Cmd-click (or Ctrl-click on Windows/Linux) to duplicate
281 +		if (e.metaKey || e.ctrlKey) {
282 +			// Calculate target position (2 cells to the right if there's room)
283 +			let newXCell = imageData.xCell + 2;
284 +			let newYCell = imageData.yCell;
285 +
286 +			// If there's not enough room to the right, try to place appropriately
287 +			if (newXCell + imageData.widthCells > GRID_COLS) {
288 +				// Try wrapping to next row
289 +				newXCell = 0;
290 +				newYCell = imageData.yCell + imageData.heightCells;
291 +
292 +				// If that goes off the bottom, place at origin
293 +				if (newYCell + imageData.heightCells > GRID_ROWS) {
294 +					newXCell = 0;
295 +					newYCell = 0;
296 +				}
297 +			}
298 +
299 +			// Create duplicate with the same image source and dimensions
300 +			const imgElement = container.querySelector('img');
301 +			const newImageData = addImage(
302 +				imgElement.src,
303 +				newXCell,
304 +				newYCell,
305 +				imageData.widthCells,
306 +				imageData.heightCells
307 +			);
308 +
309 +			// Copy pan and zoom settings from original
310 +			// Store the original settings to apply after image loads
311 +			const originalPanX = imageData.panX;
312 +			const originalPanY = imageData.panY;
313 +			const originalUserScale = imageData.userScale;
314 +
315 +			// Override the onload to copy settings
316 +			const newImg = newImageData.container.querySelector('img');
317 +			const originalOnload = newImg.onload;
318 +			newImg.onload = () => {
319 +				// Run the original onload first
320 +				if (originalOnload) originalOnload.call(newImg);
321 +
322 +				// Then apply the copied settings
323 +				newImageData.panX = originalPanX;
324 +				newImageData.panY = originalPanY;
325 +				newImageData.userScale = originalUserScale;
326 +				updateImagePosition(newImageData);
327 +			};
328 +
329 +			// If image is already loaded (cached), trigger the settings copy
330 +			if (newImg.complete && newImageData.naturalWidth > 0) {
331 +				newImageData.panX = originalPanX;
332 +				newImageData.panY = originalPanY;
333 +				newImageData.userScale = originalUserScale;
334 +				updateImagePosition(newImageData);
335 +			}
336 +
337 +			return;
338 +		}
339 +
340  		// Lock cursor to move during drag operation
341  		document.body.style.cursor = 'move';
342  		document.body.classList.add('dragging');