You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, initialZoom = "fit", bgColor = "#111111") {
// Main Container
const container = document.createElement("div");
container.style.position = "relative";
container.style.width = "100%";
container.style.height = "100%";
container.style.minHeight = "500px";
container.style.backgroundColor = bgColor;
container.style.overflow = "hidden";
container.style.fontFamily = "Arial, sans-serif";
container.style.display = "flex";
container.style.flexDirection = "column";
container.style.borderRadius = "8px";
container.style.boxShadow = "inset 0 0 30px rgba(0,0,0,0.8)";
container.style.userSelect = "none";
// Acer Branding
const brandContainer = document.createElement("div");
brandContainer.style.position = "absolute";
brandContainer.style.top = "15px";
brandContainer.style.left = "20px";
brandContainer.style.zIndex = "10";
brandContainer.style.pointerEvents = "none";
brandContainer.innerHTML = `
<span style="color:#82b440; font-weight: 800; font-size: 24px; font-family: 'Arial Black', sans-serif; letter-spacing: -1.5px; text-transform: lowercase; text-shadow: 0 2px 4px rgba(0,0,0,0.5);">acer</span>
<span style="color: #ffffff; font-weight: 300; font-size: 14px; opacity: 0.8; margin-left: 8px; text-shadow: 0 1px 3px rgba(0,0,0,0.5);">Image Viewer</span>
`;
container.appendChild(brandContainer);
// Canvas
const canvas = document.createElement("canvas");
canvas.style.flex = "1";
canvas.style.display = "block";
canvas.style.cursor = "grab";
canvas.style.width = "100%";
canvas.style.height = "100%";
container.appendChild(canvas);
const ctx = canvas.getContext("2d", { alpha: false });
// Viewer State variables
let scale = 1;
let offsetX = 0;
let offsetY = 0;
let rotation = 0;
let isDragging = false;
let dragStartX = 0;
let dragStartY = 0;
let initDone = false;
// Helper: Reset view bounds
const resetView = (mode = initialZoom) => {
if (canvas.width === 0 || canvas.height === 0 || !originalImg.width) return;
// Handle rotation bounding boxes
const isRotated = (rotation % 180 !== 0);
const imgW = isRotated ? originalImg.height : originalImg.width;
const imgH = isRotated ? originalImg.width : originalImg.height;
const maxFitScale = Math.min(canvas.width / imgW, canvas.height / imgH) * 0.95;
offsetX = canvas.width / 2;
offsetY = canvas.height / 2;
if (mode === "1:1") {
scale = 1;
} else if (mode === "fill") {
scale = Math.max(canvas.width / imgW, canvas.height / imgH);
} else {
scale = maxFitScale;
}
draw();
};
// Render original scale layout
const draw = () => {
if (!originalImg.width) return; // Prevent draw if image isn't loaded completely
// Clear with background color instead of transparent
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(offsetX, offsetY);
ctx.rotate(rotation * Math.PI / 180);
ctx.scale(scale, scale);
// Quality rendering
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
ctx.drawImage(originalImg, -originalImg.width / 2, -originalImg.height / 2);
ctx.restore();
};
// Observers & Init
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
const rect = entry.contentRect;
canvas.width = rect.width;
canvas.height = rect.height;
if (!initDone && originalImg.width) {
resetView();
initDone = true;
} else {
draw();
}
}
});
resizeObserver.observe(container);
if (!originalImg.complete) {
originalImg.addEventListener('load', () => {
if (canvas.width > 0) resetView();
});
}
// Interactivity: Drag & Pan
canvas.addEventListener("pointerdown", (e) => {
isDragging = true;
canvas.setPointerCapture(e.pointerId);
dragStartX = e.clientX - offsetX;
dragStartY = e.clientY - offsetY;
canvas.style.cursor = "grabbing";
});
canvas.addEventListener("pointermove", (e) => {
if (!isDragging) return;
offsetX = e.clientX - dragStartX;
offsetY = e.clientY - dragStartY;
draw();
});
canvas.addEventListener("pointerup", (e) => {
if(isDragging) {
isDragging = false;
canvas.releasePointerCapture(e.pointerId);
canvas.style.cursor = "grab";
}
});
// Interactivity: Wheel Zoom (Centered on Pointer)
canvas.addEventListener("wheel", (e) => {
e.preventDefault();
// Differentiate line vs pixel scrolling (trackpad vs mouse wheel)
const zoomIntensity = e.deltaMode === 1 ? 0.05 : 0.002;
const zoomFactor = Math.exp(-e.deltaY * zoomIntensity);
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
let newScale = scale * zoomFactor;
newScale = Math.max(0.01, Math.min(newScale, 100)); // Limits to prevent glitch
const ratio = newScale / scale;
const dx = mouseX - offsetX;
const dy = mouseY - offsetY;
offsetX = mouseX - dx * ratio;
offsetY = mouseY - dy * ratio;
scale = newScale;
draw();
}, { passive: false });
// Double tap to quick-reset fit
canvas.addEventListener("dblclick", () => resetView("fit"));
// UI Overlay (Toolbar Toolbar)
const toolbar = document.createElement("div");
toolbar.style.position = "absolute";
toolbar.style.bottom = "25px";
toolbar.style.left = "50%";
toolbar.style.transform = "translateX(-50%)";
toolbar.style.display = "flex";
toolbar.style.gap = "4px";
toolbar.style.padding = "6px 12px";
toolbar.style.backgroundColor = "rgba(40, 40, 40, 0.75)";
toolbar.style.backdropFilter = "blur(8px)";
toolbar.style.webkitBackdropFilter = "blur(8px)";
toolbar.style.borderRadius = "30px";
toolbar.style.boxShadow = "0 8px 32px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1)";
toolbar.style.zIndex = "10";
const createBtn = (htmlIcon, title, onClick) => {
const btn = document.createElement("button");
btn.innerHTML = htmlIcon;
btn.title = title;
btn.style.width = "38px";
btn.style.height = "38px";
btn.style.display = "flex";
btn.style.alignItems = "center";
btn.style.justifyContent = "center";
btn.style.backgroundColor = "transparent";
btn.style.color = "#eaeaea";
btn.style.border = "none";
btn.style.borderRadius = "50%";
btn.style.cursor = "pointer";
btn.style.fontSize = "16px";
btn.style.transition = "all 0.15s ease";
btn.style.outline = "none";
btn.onmouseover = () => {
btn.style.backgroundColor = "rgba(130, 180, 64, 0.4)";
btn.style.color = "#82b440"; // Acer vibrant green highlight
};
btn.onmouseout = () => {
btn.style.backgroundColor = "transparent";
btn.style.color = "#eaeaea";
};
btn.onmousedown = () => btn.style.transform = "scale(0.9)";
btn.onmouseup = () => btn.style.transform = "scale(1)";
btn.onclick = onClick;
return btn;
};
// Zoom Out
toolbar.appendChild(createBtn(
'<b style="font-size:24px; font-weight: 400; line-height: 0;">-</b>',
"Zoom Out",
() => {
scale = Math.max(0.01, scale * 0.8);
draw();
}
));
// Zoom In
toolbar.appendChild(createBtn(
'<b style="font-size:22px; font-weight: 400; line-height: 0;">+</b>',
"Zoom In",
() => {
scale = Math.min(100, scale * 1.25);
draw();
}
));
// Separator line
const sep1 = document.createElement("div");
sep1.style.width = "1px";
sep1.style.backgroundColor = "rgba(255,255,255,0.1)";
sep1.style.margin = "4px";
toolbar.appendChild(sep1);
// Fit View
toolbar.appendChild(createBtn(
'<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>',
"Fit View",
() => resetView("fit")
));
// Custom 1:1 Pixel Mapping
toolbar.appendChild(createBtn(
'<b style="font-size:12px; font-family: monospace;">1:1</b>',
"Original Size",
() => resetView("1:1")
));
// Separator line
const sep2 = document.createElement("div");
sep2.style.width = "1px";
sep2.style.backgroundColor = "rgba(255,255,255,0.1)";
sep2.style.margin = "4px";
toolbar.appendChild(sep2);
// Rotate
toolbar.appendChild(createBtn(
'<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12a10 10 0 1 1 10 10 10 10 0 0 1-10-10"></path><path d="M12 2v10"></path></svg>',
"Rotate 90°",
() => {
rotation = (rotation + 90) % 360;
resetView("fit");
}
));
container.appendChild(toolbar);
return container;
}
Apply Changes