Shopify themes, liquid, logos, and UX
<div class="container"> <div class="flag-customizer"> <h1 style="color: black; font-weight: bold">Anpassa din flagga</h1> <h5 style="color: black; font-weight: bold">Funktionen tillåter dig både att zooma och justera placeringen på länderna</h5> <h6 style="color: black; font-weight: bold">(Obs, det kan ibland ta en stund innan länderna visas när du väljer dem. Starta om sidan om tekniska fel uppstår)</h6> <label for="flag1" style="color: black; font-weight: bold">Land 1:</label> <select id="flag1" style="color: black; font-weight: bold"> <option>Välj</option> </select> <br> <label for="flag2" style="color: black; font-weight: bold">Land 2:</label> <select id="flag2" style="color: black; font-weight: bold"> <option>Välj</option> </select> <div class="flag-container"> <canvas id="flagCanvas1" width="5906" height="3544"></canvas> <canvas id="flagCanvas2" width="5906" height="3544"></canvas> </div> <button id="uploadFlagBtn">Spara</button> </div> <style> #flagCanvas1, #flagCanvas2 { position: absolute; width: 100%; height: 100%; } #flagCanvas1 { clip-path: polygon(100% 0, 0 0, 0 100%); } #flagCanvas2 { clip-path: polygon(0 100%, 100% 0, 100% 100%); } </style> <script> // Funktion för att skapa alternativ function populateSelect(selectId) { const selectElement = document.getElementById(selectId); countries.forEach(country => { const option = document.createElement("option"); option.value = country.value; option.textContent = country.label; selectElement.appendChild(option); }); } // När sidan har laddats document.addEventListener("DOMContentLoaded", function () { populateSelect("flag1"); // Fyll första dropdown populateSelect("flag2"); // Fyll andra dropdown }); </script> <script> fetch('{{ "flags.json" | asset_url }}?v={{ settings.theme_version }}') .then(response => response.json()) .then(flags => { // Exempel: använd flaggorna console.log(flags); // Ladda flaggor i select-element const flag1Select = document.getElementById("flag1"); const flag2Select = document.getElementById("flag2"); for (const [key, url] of Object.entries(flags)) { const option1 = document.createElement("option"); option1.value = key; option1.textContent = key.replace(/_/g, " "); flag1Select.appendChild(option1); const option2 = document.createElement("option"); option2.value = key; option2.textContent = key.replace(/_/g, " "); flag2Select.appendChild(option2); } }) .catch(error => console.error("Kunde inte läsa flaggdata:", error)); </script> <script> document.addEventListener("DOMContentLoaded", function() { const canvas1 = document.getElementById("flagCanvas1"); const ctx1 = canvas1.getContext("2d"); const canvas2 = document.getElementById("flagCanvas2"); const ctx2 = canvas2.getContext("2d"); const flag1Select = document.getElementById("flag1"); const flag2Select = document.getElementById("flag2"); let flag1Image = new Image(); flag1Image.crossOrigin = "anonymous"; let flag2Image = new Image(); flag2Image.crossOrigin = "anonymous"; let flag1Zoom = 3, flag1OffsetX = -5906, flag1OffsetY = -3544; let flag2Zoom = 3, flag2OffsetX = -5906, flag2OffsetY = -3544; // Load selected flags flag1Select.addEventListener("change", function() { flag1Image.src=flags[flag1Select.value]; }); flag2Select.addEventListener("change", function() { flag2Image.src=flags[flag2Select.value]; }); // Set initial flags flag1Image.src=flags[flag1Select.value]; flag2Image.src=flags[flag2Select.value]; function drawFlag1() { ctx1.clearRect(0, 0, canvas1.width, canvas1.height); ctx1.save(); ctx1.translate(flag1OffsetX, flag1OffsetY); ctx1.scale(flag1Zoom, flag1Zoom); ctx1.drawImage(flag1Image, 0, 0, canvas1.width, canvas1.height); ctx1.restore(); } function drawFlag2() { ctx2.clearRect(0, 0, canvas2.width, canvas2.height); ctx2.save(); ctx2.translate(flag2OffsetX, flag2OffsetY); ctx2.scale(flag2Zoom, flag2Zoom); ctx2.drawImage(flag2Image, 0, 0, canvas2.width, canvas2.height); ctx2.restore(); } flag1Image.onload = drawFlag1; flag2Image.onload = drawFlag2; // Check if flags are selected function isFlagSelected() { return ( flag1Select.value !== "Välj" && flag2Select.value !== "Välj" && flag1Select.value && flag2Select.value ); } // Zoom and move functionality for desktop canvas1.addEventListener("wheel", function(e) { e.preventDefault(); flag1Zoom += e.deltaY * -0.005; drawFlag1(); }); canvas2.addEventListener("wheel", function(e) { e.preventDefault(); flag2Zoom += e.deltaY * -0.005; drawFlag2(); }); // Drag and zoom functionality for canvas1 let isDragging1 = false, startX1, startY1; canvas1.addEventListener("mousedown", function(e) { if (!isFlagSelected()) return; // Disable movement if no flags are selected isDragging1 = true; startX1 = e.offsetX*5 - flag1OffsetX; startY1 = e.offsetY*5 - flag1OffsetY; }); canvas1.addEventListener("mousemove", function(e) { if (isDragging1) { flag1OffsetX = e.offsetX*5 - startX1; flag1OffsetY = e.offsetY*5 - startY1; drawFlag1(); } }); canvas1.addEventListener("mouseup", function() { isDragging1 = false; }); canvas1.addEventListener("mouseleave", function() { isDragging1 = false; }); // Touch events for drag and zoom on canvas1 let initialTouchDistance1 = 0; canvas1.addEventListener("touchstart", function(e) { if (!isFlagSelected()) return; // Disable movement if no flags are selected if (e.touches.length === 1) { // Single finger touch for dragging isDragging1 = true; startX1 = e.touches[0].clientX*5 - flag1OffsetX; startY1 = e.touches[0].clientY*5 - flag1OffsetY; } else if (e.touches.length === 2) { // Two finger touch for zooming isDragging1 = false; initialTouchDistance1 = Math.hypot( e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY ); } }); canvas1.addEventListener("touchmove", function(e) { if (isDragging1 && e.touches.length === 1) { flag1OffsetX = e.touches[0].clientX*5 - startX1; flag1OffsetY = e.touches[0].clientY*5 - startY1; drawFlag1(); } else if (e.touches.length === 2) { const currentTouchDistance1 = Math.hypot( e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY ); const zoomFactor = 0.2; flag1Zoom *= 1 + (zoomFactor * (currentTouchDistance1 / initialTouchDistance1 - 1)); initialTouchDistance1 = currentTouchDistance1; drawFlag1(); } }); canvas1.addEventListener("touchend", function() { isDragging1 = false; }); // Drag and zoom functionality for canvas2 let isDragging2 = false, startX2, startY2; canvas2.addEventListener("mousedown", function(e) { if (!isFlagSelected()) return; // Disable movement if no flags are selected isDragging2 = true; startX2 = e.offsetX*5 - flag2OffsetX; startY2 = e.offsetY*5 - flag2OffsetY; }); canvas2.addEventListener("mousemove", function(e) { if (isDragging2) { flag2OffsetX = e.offsetX*5 - startX2; flag2OffsetY = e.offsetY*5 - startY2; drawFlag2(); } }); canvas2.addEventListener("mouseup", function() { isDragging2 = false; }); canvas2.addEventListener("mouseleave", function() { isDragging2 = false; }); // Touch events for drag and zoom on canvas2 let initialTouchDistance2 = 0; canvas2.addEventListener("touchstart", function(e) { if (!isFlagSelected()) return; // Disable movement if no flags are selected if (e.touches.length === 1) { isDragging2 = true; startX2 = e.touches[0].clientX*5 - flag2OffsetX; startY2 = e.touches[0].clientY*5 - flag2OffsetY; } else if (e.touches.length === 2) { isDragging2 = false; initialTouchDistance2 = Math.hypot( e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY ); } }); canvas2.addEventListener("touchmove", function(e) { if (isDragging2 && e.touches.length === 1) { flag2OffsetX = e.touches[0].clientX*5 - startX2; flag2OffsetY = e.touches[0].clientY*5 - startY2; drawFlag2(); } else if (e.touches.length === 2) { const currentTouchDistance2 = Math.hypot( e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY ); const zoomFactor = 0.2; flag2Zoom *= 1 + (zoomFactor * (currentTouchDistance2 / initialTouchDistance2 - 1)); initialTouchDistance2 = currentTouchDistance2; drawFlag2(); } }); canvas2.addEventListener("touchend", function() { isDragging2 = false; }); // Prevent page movement during touch interactions document.addEventListener("touchmove", function(e) { if (e.target.closest(".flag-container")) { e.preventDefault(); } }, { passive: false }); // Funktionen som sparar flagganpassningen document.getElementById("uploadFlagBtn").addEventListener("click", function () { const flag1Value = flag1Select.value; const flag2Value = flag2Select.value; if (!flag1Value || flag1Value === "Välj" || !flag2Value || flag2Value === "Välj") { alert("Du måste välja två flaggor innan du sparar!"); // Visa ett meddelande return; // Stoppa funktionen } const combinedCanvas = document.createElement("canvas"); combinedCanvas.width = 5906; // Match canvas dimensions combinedCanvas.height = 3544; const combinedCtx = combinedCanvas.getContext("2d"); // Combine the two canvases combinedCtx.save(); combinedCtx.beginPath(); combinedCtx.moveTo(0, combinedCanvas.height); combinedCtx.lineTo(combinedCanvas.width, 0); combinedCtx.lineTo(0, 0); combinedCtx.closePath(); combinedCtx.clip(); combinedCtx.drawImage(document.getElementById("flagCanvas1"), 0, 0, combinedCanvas.width, combinedCanvas.height); combinedCtx.restore(); combinedCtx.save(); combinedCtx.beginPath(); combinedCtx.moveTo(combinedCanvas.width, 0); combinedCtx.lineTo(0, combinedCanvas.height); combinedCtx.lineTo(combinedCanvas.width, combinedCanvas.height); combinedCtx.closePath(); combinedCtx.clip(); combinedCtx.drawImage(document.getElementById("flagCanvas2"), 0, 0, combinedCanvas.width, combinedCanvas.height); combinedCtx.restore(); // Convert the canvas to a Blob combinedCanvas.toBlob(function (blob) { // Prepare the file for upload const file = new File([blob], "customized_flag.png", { type: "image/png" }); // Find the Upload Lift input element (FilePond) const uploadInput = document.querySelector('input[type="file"].filepond--browser'); if (uploadInput) { // Use FilePond's File API to add the file programmatically const dataTransfer = new DataTransfer(); dataTransfer.items.add(file); uploadInput.files = dataTransfer.files; // Trigger the change event to start the upload process const event = new Event("change", { bubbles: true }); uploadInput.dispatchEvent(event); alert("Din flagga har sparats! Scrolla nedåt för att slutföra din beställning."); } else { alert("Kunde inte hitta uppladdningsfältet. Kontrollera din konfiguration."); } }, "image/png"); }); }); </script>
What is wrong with my code, the function is to allow the customer to choose 2 countries and make 1 flag out of it. For some customers the function works but for others it doesn't work, they don't get the flag images visible and they can't do anything. How do I fix this problem, please help.
@Amel05 HI,
Here's a cleaned-up and fixed version of your code that:
<!-- Optional: Loading message -->
<p id="loadingMsg">Laddar flaggor...</p>
<select id="flag1"></select>
<select id="flag2"></select>
<br><br>
<canvas id="canvas" width="400" height="300"></canvas>
<br>
<button id="saveButton">Spara flagga</button>
<script>
fetch('{{ "flags.json" | asset_url }}?v={{ settings.theme_version }}')
.then(response => response.json())
.then(flags => {
const flag1Select = document.getElementById("flag1");
const flag2Select = document.getElementById("flag2");
for (const [key, url] of Object.entries(flags)) {
const option1 = document.createElement("option");
option1.value = key;
option1.textContent = key.replace(/_/g, " ");
flag1Select.appendChild(option1);
const option2 = document.createElement("option");
option2.value = key;
option2.textContent = key.replace(/_/g, " ");
flag2Select.appendChild(option2);
}
document.getElementById("loadingMsg").style.display = "none";
initializeCanvasLogic(flags);
})
.catch(error => {
console.error("Kunde inte läsa flaggdata:", error);
alert("Kunde inte ladda flaggdata. Vänligen försök igen senare.");
});
function initializeCanvasLogic(flags) {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let scale = 1, offsetX = 0, offsetY = 0, isDragging = false, startX, startY;
const flag1Image = new Image();
const flag2Image = new Image();
const flag1Select = document.getElementById("flag1");
const flag2Select = document.getElementById("flag2");
flag1Select.addEventListener("change", () => loadImage(flag1Image, flags[flag1Select.value]));
flag2Select.addEventListener("change", () => loadImage(flag2Image, flags[flag2Select.value]));
function loadImage(image, src) {
image.crossOrigin = "anonymous";
image.src=src;
image.onerror = () => alert("Kunde inte ladda en flagga. Välj ett annat land eller kontrollera din internetanslutning.");
image.onload = draw;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(offsetX, offsetY);
ctx.scale(scale, scale);
// Draw flag1 on left diagonal
ctx.save();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(canvas.width, 0);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(flag1Image, 0, 0, canvas.width, canvas.height);
ctx.restore();
// Draw flag2 on right diagonal
ctx.save();
ctx.beginPath();
ctx.moveTo(canvas.width, 0);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.clip();
ctx.drawImage(flag2Image, 0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.restore();
}
canvas.addEventListener("wheel", (e) => {
e.preventDefault();
const delta = e.deltaY < 0 ? 0.1 : -0.1;
scale = Math.max(0.1, scale + delta);
draw();
});
canvas.addEventListener("mousedown", (e) => {
isDragging = true;
startX = e.offsetX;
startY = e.offsetY;
});
canvas.addEventListener("mousemove", (e) => {
if (isDragging) {
offsetX += (e.offsetX - startX);
offsetY += (e.offsetY - startY);
startX = e.offsetX;
startY = e.offsetY;
draw();
}
});
canvas.addEventListener("mouseup", () => isDragging = false);
canvas.addEventListener("mouseout", () => isDragging = false);
document.getElementById("saveButton").addEventListener("click", () => {
const link = document.createElement("a");
link.download = "kombinerad_flagga.png";
link.href = canvas.toDataURL("image/png");
link.click();
});
}
</script>
Please replace the previous code with this one.
<div class="container">
<div class="flag-customizer">
<h1 style="color: black; font-weight: bold">Anpassa din flagga</h1>
<h5 style="color: black; font-weight: bold">Funktionen tillåter dig både att zooma och justera placeringen på länderna</h5>
<h6 style="color: black; font-weight: bold">(Obs, det kan ibland ta en stund innan länderna visas när du väljer dem. Starta om sidan om tekniska fel uppstår)</h6>
<label for="flag1" style="color: black; font-weight: bold">Land 1:</label>
<select id="flag1" style="color: black; font-weight: bold">
<option value="">Välj</option>
</select>
<br>
<label for="flag2" style="color: black; font-weight: bold">Land 2:</label>
<select id="flag2" style="color: black; font-weight: bold">
<option value="">Välj</option>
</select>
<div class="flag-container">
<canvas id="flagCanvas1" width="5906" height="3544"></canvas>
<canvas id="flagCanvas2" width="5906" height="3544"></canvas>
<div id="loadingMessage" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: black; font-weight: bold;">
Laddar flagga...
</div>
</div>
<button id="uploadFlagBtn">Spara</button>
</div>
</div>
<style>
.flag-container {
position: relative;
width: 100%;
height: 400px; /* Fixed height for better control */
border: 1px solid #ccc;
overflow: hidden;
margin-top: 20px;
}
#flagCanvas1, #flagCanvas2 {
position: absolute;
width: 100%;
height: 100%;
}
#flagCanvas1 {
clip-path: polygon(100% 0, 0 0, 0 100%);
}
#flagCanvas2 {
clip-path: polygon(0 100%, 100% 0, 100% 100%);
}
</style>
<script>
// Global flags object
let flags = {};
// Function to load flags JSON
function loadFlags() {
return fetch('{{ "flags.json" | asset_url }}?v={{ settings.theme_version }}')
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then(loadedFlags => {
flags = loadedFlags;
return flags;
});
}
// Function to populate select dropdowns
function populateSelects() {
const flag1Select = document.getElementById("flag1");
const flag2Select = document.getElementById("flag2");
// Clear existing options except first
while (flag1Select.options.length > 1) flag1Select.remove(1);
while (flag2Select.options.length > 1) flag2Select.remove(1);
for (const [key, url] of Object.entries(flags)) {
const option1 = document.createElement("option");
option1.value = key;
option1.textContent = key.replace(/_/g, " ");
flag1Select.appendChild(option1);
const option2 = document.createElement("option");
option2.value = key;
option2.textContent = key.replace(/_/g, " ");
flag2Select.appendChild(option2);
}
}
// Function to load an image with error handling
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Failed to load image: ${src}`));
img.src=src;
});
}
// Main function when DOM is loaded
document.addEventListener("DOMContentLoaded", async function() {
try {
// Show loading state
const loadingMessage = document.getElementById("loadingMessage");
// Load flags data
await loadFlags();
populateSelects();
const canvas1 = document.getElementById("flagCanvas1");
const ctx1 = canvas1.getContext("2d");
const canvas2 = document.getElementById("flagCanvas2");
const ctx2 = canvas2.getContext("2d");
const flag1Select = document.getElementById("flag1");
const flag2Select = document.getElementById("flag2");
let flag1Image = null;
let flag2Image = null;
let flag1Zoom = 1, flag1OffsetX = 0, flag1OffsetY = 0;
let flag2Zoom = 1, flag2OffsetX = 0, flag2OffsetY = 0;
// Draw flag with current settings
function drawFlag1() {
if (!flag1Image) return;
ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
ctx1.save();
ctx1.translate(flag1OffsetX, flag1OffsetY);
ctx1.scale(flag1Zoom, flag1Zoom);
ctx1.drawImage(flag1Image, 0, 0, canvas1.width, canvas1.height);
ctx1.restore();
}
function drawFlag2() {
if (!flag2Image) return;
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
ctx2.save();
ctx2.translate(flag2OffsetX, flag2OffsetY);
ctx2.scale(flag2Zoom, flag2Zoom);
ctx2.drawImage(flag2Image, 0, 0, canvas2.width, canvas2.height);
ctx2.restore();
}
// Load selected flags with error handling
flag1Select.addEventListener("change", async function() {
if (!this.value) return;
try {
loadingMessage.style.display = 'block';
flag1Image = await loadImage(flags[this.value]);
// Reset position and zoom for new flag
flag1Zoom = 1;
flag1OffsetX = 0;
flag1OffsetY = 0;
drawFlag1();
} catch (error) {
console.error("Error loading flag 1:", error);
alert("Kunde inte ladda flaggan. Försök igen.");
} finally {
loadingMessage.style.display = 'none';
}
});
flag2Select.addEventListener("change", async function() {
if (!this.value) return;
try {
loadingMessage.style.display = 'block';
flag2Image = await loadImage(flags[this.value]);
// Reset position and zoom for new flag
flag2Zoom = 1;
flag2OffsetX = 0;
flag2OffsetY = 0;
drawFlag2();
} catch (error) {
console.error("Error loading flag 2:", error);
alert("Kunde inte ladda flaggan. Försök igen.");
} finally {
loadingMessage.style.display = 'none';
}
});
// Check if flags are selected
function isFlagSelected() {
return flag1Image && flag2Image;
}
// Zoom with limits
function applyZoom(zoom, delta, currentZoom) {
const newZoom = currentZoom + delta * -0.005;
return Math.max(0.1, Math.min(10, newZoom)); // Limit zoom between 0.1 and 10
}
// Zoom functionality for desktop
canvas1.addEventListener("wheel", function(e) {
e.preventDefault();
if (!isFlagSelected()) return;
flag1Zoom = applyZoom(flag1Zoom, e.deltaY, flag1Zoom);
drawFlag1();
});
canvas2.addEventListener("wheel", function(e) {
e.preventDefault();
if (!isFlagSelected()) return;
flag2Zoom = applyZoom(flag2Zoom, e.deltaY, flag2Zoom);
drawFlag2();
});
// Drag functionality for canvas1
let isDragging1 = false, startX1, startY1;
canvas1.addEventListener("mousedown", function(e) {
if (!isFlagSelected()) return;
isDragging1 = true;
startX1 = e.offsetX - flag1OffsetX;
startY1 = e.offsetY - flag1OffsetY;
});
canvas1.addEventListener("mousemove", function(e) {
if (isDragging1) {
flag1OffsetX = e.offsetX - startX1;
flag1OffsetY = e.offsetY - startY1;
drawFlag1();
}
});
canvas1.addEventListener("mouseup", function() { isDragging1 = false; });
canvas1.addEventListener("mouseleave", function() { isDragging1 = false; });
// Touch events for canvas1
let initialTouchDistance1 = 0;
canvas1.addEventListener("touchstart", function(e) {
if (!isFlagSelected()) return;
if (e.touches.length === 1) {
isDragging1 = true;
const touch = e.touches[0];
const rect = canvas1.getBoundingClientRect();
startX1 = touch.clientX - rect.left - flag1OffsetX;
startY1 = touch.clientY - rect.top - flag1OffsetY;
} else if (e.touches.length === 2) {
isDragging1 = false;
initialTouchDistance1 = Math.hypot(
e.touches[0].clientX - e.touches[1].clientX,
e.touches[0].clientY - e.touches[1].clientY
);
}
});
canvas1.addEventListener("touchmove", function(e) {
if (!isFlagSelected()) return;
e.preventDefault();
if (isDragging1 && e.touches.length === 1) {
const touch = e.touches[0];
const rect = canvas1.getBoundingClientRect();
flag1OffsetX = touch.clientX - rect.left - startX1;
flag1OffsetY = touch.clientY - rect.top - startY1;
drawFlag1();
} else if (e.touches.length === 2) {
const currentTouchDistance1 = Math.hypot(
e.touches[0].clientX - e.touches[1].clientX,
e.touches[0].clientY - e.touches[1].clientY
);
const zoomFactor = 0.01; // More subtle zoom
flag1Zoom = applyZoom(flag1Zoom, (currentTouchDistance1 / initialTouchDistance1 - 1) * 100, flag1Zoom);
initialTouchDistance1 = currentTouchDistance1;
drawFlag1();
}
});
canvas1.addEventListener("touchend", function() { isDragging1 = false; });
// Drag functionality for canvas2
let isDragging2 = false, startX2, startY2;
canvas2.addEventListener("mousedown", function(e) {
if (!isFlagSelected()) return;
isDragging2 = true;
startX2 = e.offsetX - flag2OffsetX;
startY2 = e.offsetY - flag2OffsetY;
});
canvas2.addEventListener("mousemove", function(e) {
if (isDragging2) {
flag2OffsetX = e.offsetX - startX2;
flag2OffsetY = e.offsetY - startY2;
drawFlag2();
}
});
canvas2.addEventListener("mouseup", function() { isDragging2 = false; });
canvas2.addEventListener("mouseleave", function() { isDragging2 = false; });
// Touch events for canvas2
let initialTouchDistance2 = 0;
canvas2.addEventListener("touchstart", function(e) {
if (!isFlagSelected()) return;
if (e.touches.length === 1) {
isDragging2 = true;
const touch = e.touches[0];
const rect = canvas2.getBoundingClientRect();
startX2 = touch.clientX - rect.left - flag2OffsetX;
startY2 = touch.clientY - rect.top - flag2OffsetY;
} else if (e.touches.length === 2) {
isDragging2 = false;
initialTouchDistance2 = Math.hypot(
e.touches[0].clientX - e.touches[1].clientX,
e.touches[0].clientY - e.touches[1].clientY
);
}
});
canvas2.addEventListener("touchmove", function(e) {
if (!isFlagSelected()) return;
e.preventDefault();
if (isDragging2 && e.touches.length === 1) {
const touch = e.touches[0];
const rect = canvas2.getBoundingClientRect();
flag2OffsetX = touch.clientX - rect.left - startX2;
flag2OffsetY = touch.clientY - rect.top - startY2;
drawFlag2();
} else if (e.touches.length === 2) {
const currentTouchDistance2 = Math.hypot(
e.touches[0].clientX - e.touches[1].clientX,
e.touches[0].clientY - e.touches[1].clientY
);
const zoomFactor = 0.01; // More subtle zoom
flag2Zoom = applyZoom(flag2Zoom, (currentTouchDistance2 / initialTouchDistance2 - 1) * 100, flag2Zoom);
initialTouchDistance2 = currentTouchDistance2;
drawFlag2();
}
});
canvas2.addEventListener("touchend", function() { isDragging2 = false; });
// Save flag function
document.getElementById("uploadFlagBtn").addEventListener("click", function() {
if (!isFlagSelected()) {
alert("Du måste välja två flaggor innan du sparar!");
return;
}
const combinedCanvas = document.createElement("canvas");
combinedCanvas.width = 5906;
combinedCanvas.height = 3544;
const combinedCtx = combinedCanvas.getContext("2d");
// Combine the two canvases
combinedCtx.save();
combinedCtx.beginPath();
combinedCtx.moveTo(0, combinedCanvas.height);
combinedCtx.lineTo(combinedCanvas.width, 0);
combinedCtx.lineTo(0, 0);
combinedCtx.closePath();
combinedCtx.clip();
combinedCtx.drawImage(canvas1, 0, 0, combinedCanvas.width, combinedCanvas.height);
combinedCtx.restore();
combinedCtx.save();
combinedCtx.beginPath();
combinedCtx.moveTo(combinedCanvas.width, 0);
combinedCtx.lineTo(0, combinedCanvas.height);
combinedCtx.lineTo(combinedCanvas.width, combinedCanvas.height);
combinedCtx.closePath();
combinedCtx.clip();
combinedCtx.drawImage(canvas2, 0, 0, combinedCanvas.width, combinedCanvas.height);
combinedCtx.restore();
// Convert to Blob
combinedCanvas.toBlob(function(blob) {
const file = new File([blob], "customized_flag.png", { type: "image/png" });
const uploadInput = document.querySelector('input[type="file"].filepond--browser');
if (uploadInput) {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
uploadInput.files = dataTransfer.files;
uploadInput.dispatchEvent(new Event("change", { bubbles: true }));
alert("Din flagga har sparats! Scrolla nedåt för att slutföra din beställning.");
} else {
alert("Kunde inte hitta uppladdningsfältet. Kontrollera din konfiguration.");
}
}, "image/png");
});
} catch (error) {
console.error("Initialization error:", error);
alert("Ett fel uppstod vid initiering av flagganpassaren. Ladda om sidan och försök igen.");
}
});
</script>
What I did here:
By applying these changes I make sur eit's work well.
Let me know if it work for you. If not I will provide you anothe rsolution code.
Thanks
Now I can't choose any flag, but it isn't flags.json, it is flags.js.
Could you please share the collab code in the p/m so that I can take a look and fix it.
Thanks
Learn how to build powerful custom workflows in Shopify Flow with expert guidance from ...
By Jacqui May 7, 2025Did You Know? May is named after Maia, the Roman goddess of growth and flourishing! ...
By JasonH May 2, 2025Discover opportunities to improve SEO with new guidance available from Shopify’s growth...
By Jacqui May 1, 2025