const capImageSize = 50; const halfCapImageSize = capImageSize / 2; const numberOfCaps = 1875; const numberOfColumns = 40; const numberOfRows = Math.ceil(numberOfCaps / numberOfColumns); const effectiveHeight = Math.ceil(capImageSize*Math.cos(Math.PI/6)); function sourcePath(capId) { return "thumbnails/" + `${capId}`.padStart(4, '0') + '.jpg' } function createImage(position) { return '' }; function setCapImageAtPosition(capId, position) { elements[position].src = sourcePath(capId); capPositions[position] = capId; } function getCapIdAtPosition(position) { return capPositions[position]; } const imageCanvas = document.getElementById("image-canvas"); var capPositions = Array.from( {length: numberOfCaps}, (_, index) => index + 1 ); imageCanvas.innerHTML += capPositions.map(createImage).join(""); var selectedPosition = null; const elements = imageCanvas.getElementsByTagName("img"); const selectedCapCircle = document.getElementById("selected-cap-circle"); imageCanvas.addEventListener("click", function(event) { const yOffset = 50; const xPosition = event.clientX - imageCanvas.getBoundingClientRect().left; const yPosition = event.clientY - imageCanvas.getBoundingClientRect().top + yOffset; var row = Math.floor(yPosition / effectiveHeight); var rowIsEven = (row % 2 == 0) const adjustedX = rowIsEven ? xPosition - halfCapImageSize : xPosition; var column = Math.floor(adjustedX / capImageSize); const rowRemainder = yPosition % effectiveHeight - halfCapImageSize; const columnRemainder = adjustedX % capImageSize - halfCapImageSize; const distanceToCenter = Math.sqrt(rowRemainder**2 + columnRemainder**2); if (distanceToCenter > halfCapImageSize && rowRemainder < 6 - halfCapImageSize) { // Move to the top left cap row -= 1; if (!rowIsEven && (columnRemainder < 0)) { // Move to the top right cap column -= 1; } if (rowIsEven && (columnRemainder > 0)) { // Move to the top left cap column += 1; } rowIsEven = !rowIsEven } if (row < 0 || row >= numberOfRows) { return; } if (column < 0 || column >= numberOfColumns) { return; } const currentPosition = row * numberOfColumns + column; if (selectedPosition === null) { selectedPosition = currentPosition; const circlePositionX = rowIsEven ? column * capImageSize + halfCapImageSize : column * capImageSize; const circlePositionY = row * effectiveHeight; selectedCapCircle.style.left = circlePositionX + "px"; selectedCapCircle.style.top = circlePositionY + "px"; selectedCapCircle.style.display = "block"; return; } selectedCapCircle.style.display = "none"; if (currentPosition === selectedPosition) { selectedPosition = null; return; } // Switch cap images const currentCapId = getCapIdAtPosition(currentPosition); const selectedCapId = getCapIdAtPosition(selectedPosition); setCapImageAtPosition(selectedCapId, currentPosition); setCapImageAtPosition(currentCapId, selectedPosition); selectedPosition = null; }); function averageColor(imageElement) { var canvas = document.createElement('canvas'); var context = canvas.getContext && canvas.getContext('2d'); if (!context) { return { r: 255, g: 0, b: 0 }; } // Set the height and width equal // to that of the canvas and the image var height = canvas.height = imageElement.naturalHeight || imageElement.offsetHeight || imageElement.height; var width = canvas.width = imageElement.naturalWidth || imageElement.offsetWidth || imageElement.width; // Draw the image to the canvas context.drawImage(imageElement, 0, 0); // Get the data of the image try { var imgData = context.getImageData(0, 0, width, height); } catch(e) { /* security error, img on diff domain */alert('x'); return { r: 255, g: 0, b: 0 }; } // Get the length of image data object var length = imgData.data.length; const pixelCount = height * width; const halfX = width / 2; const halfY = height / 2; var rgb = { r: 0, g: 0, b: 0 }; var count = 0; for (var i = 0; i < pixelCount; i += 1) { // Exclude everything outside of circle const x = i % width - halfX; const y = Math.floor(i / width) - halfY; const distanceToCenter = Math.sqrt(x**2 + y**2); if (distanceToCenter > halfY) { continue; } // Sum all values of the colour const offset = 4 * i; rgb.r += imgData.data[offset]; rgb.g += imgData.data[offset + 1]; rgb.b += imgData.data[offset + 2]; count += 1; } // Find the averages rgb.r = Math.floor(rgb.r / count); rgb.g = Math.floor(rgb.g / count); rgb.b = Math.floor(rgb.b / count); return rgb; } for (let i = 0; i < capPositions.length; i += 1) { const element = elements[i]; element.onload = function() { const rgb = averageColor(element); const color = `rgb(${rgb.r},${rgb.g},${rgb.b})`; element.style.backgroundColor = color; } } var showColors = false; function toggleColors() { showColors = !showColors; const padding = showColors ? "50px" : "0px"; for (let i = 0; i < capPositions.length; i += 1) { elements[i].style.paddingLeft = padding; } }