NICEY DIY STUDIO
Create Your Bracelet
Design your own bracelet 💗
LIVE PREVIEW
Your Bracelet
♡
Choose your beads
Tap a bead below to begin
✦ Tap bead to remove
✦ Hold & drag anywhere
✦ Position stays where you leave it
DIY BEADS
Choose Your Beads
0
/
18
(function(){
const root =
document.getElementById(
'NiceyDIY-template--16375217815747__nicey_diy_bracelet_RXVYxt'
);
if(!root) return;
const bracelet =
root.querySelector(
'[data-bracelet]'
);
const empty =
root.querySelector(
'[data-empty]'
);
const countEls =
root.querySelectorAll(
'[data-count]'
);
const priceEl =
root.querySelector(
'[data-price]'
);
const message =
root.querySelector(
'[data-message]'
);
const clearBtn =
root.querySelector(
'[data-clear]'
);
const undoBtn =
root.querySelector(
'[data-undo]'
);
const cartBtn =
root.querySelector(
'[data-add-cart]'
);
const beadButtons =
root.querySelectorAll(
'[data-bead-button]'
);
const maxBeads =
Number(
18
);
const basePrice =
Number(
0
);
const variantId =
null
;
let beads = [];
let history = [];
function money(value){
return '$' +
Number(value).toFixed(2);
}
function showMessage(text){
message.textContent =
text;
clearTimeout(
message._timer
);
message._timer =
setTimeout(
function(){
message.textContent =
'';
},
2200
);
}
function saveHistory(){
history.push(
beads.map(
function(bead){
return {
name:bead.name,
price:bead.price,
image:bead.image,
uid:bead.uid,
x:bead.x,
y:bead.y,
manual:bead.manual
};
}
)
);
if(history.length > 30){
history.shift();
}
}
function getLayout(){
const rect =
bracelet.getBoundingClientRect();
const centerX =
rect.width / 2;
const centerY =
rect.height / 2;
const mobile =
rect.width < 500;
const radiusX =
Math.min(
rect.width *
(mobile ? .35 : .36),
mobile ? 118 : 175
);
const radiusY =
Math.min(
rect.height *
(mobile ? .34 : .35),
mobile ? 98 : 145
);
return {
rect,
centerX,
centerY,
radiusX,
radiusY
};
}
function autoPositionNewBeads(){
const layout =
getLayout();
const autoBeads =
beads.filter(
function(bead){
return !bead.manual;
}
);
autoBeads.forEach(
function(bead,index){
const angle =
(
index /
Math.max(
autoBeads.length,
1
)
) *
Math.PI *
2 -
Math.PI /
2;
bead.x =
layout.centerX +
Math.cos(angle) *
layout.radiusX;
bead.y =
layout.centerY +
Math.sin(angle) *
layout.radiusY;
}
);
}
function renderBracelet(){
bracelet
.querySelectorAll(
'.bracelet-bead'
)
.forEach(
function(el){
el.remove();
}
);
if(beads.length === 0){
empty.style.display =
'flex';
}else{
empty.style.display =
'none';
}
autoPositionNewBeads();
let total =
basePrice;
beads.forEach(
function(bead){
total +=
Number(
bead.price || 0
);
}
);
countEls.forEach(
function(el){
el.textContent =
beads.length;
}
);
priceEl.textContent =
money(total);
beads.forEach(
function(bead,index){
const el =
document.createElement(
'button'
);
el.type =
'button';
el.className =
'bracelet-bead';
el.style.left =
bead.x + 'px';
el.style.top =
bead.y + 'px';
const img =
document.createElement(
'img'
);
img.src =
bead.image;
img.alt =
bead.name;
el.appendChild(img);
enableFreeDrag(
el,
bead,
index
);
bracelet.appendChild(
el
);
}
);
}
function enableFreeDrag(
el,
bead,
index
){
let dragging =
false;
let moved =
false;
let startX =
0;
let startY =
0;
let pointerId =
null;
function down(e){
if(
e.pointerType ===
'mouse' &&
e.button !== 0
){
return;
}
dragging =
true;
moved =
false;
pointerId =
e.pointerId;
startX =
e.clientX;
startY =
e.clientY;
el.classList.add(
'is-dragging'
);
document.addEventListener(
'pointermove',
move,
{
passive:false
}
);
document.addEventListener(
'pointerup',
up
);
document.addEventListener(
'pointercancel',
cancel
);
e.preventDefault();
e.stopPropagation();
}
function move(e){
if(!dragging) return;
if(
e.pointerId !==
pointerId
){
return;
}
const dx =
e.clientX -
startX;
const dy =
e.clientY -
startY;
if(
Math.sqrt(
dx * dx +
dy * dy
) > 5
){
moved =
true;
}
const rect =
bracelet.getBoundingClientRect();
const radius =
el.offsetWidth /
2;
let x =
e.clientX -
rect.left;
let y =
e.clientY -
rect.top;
x =
Math.max(
radius,
Math.min(
rect.width -
radius,
x
)
);
y =
Math.max(
radius,
Math.min(
rect.height -
radius,
y
)
);
el.style.left =
x + 'px';
el.style.top =
y + 'px';
e.preventDefault();
}
function up(e){
if(!dragging) return;
if(
e.pointerId !==
pointerId
){
return;
}
cleanup();
if(!moved){
saveHistory();
beads.splice(
index,
1
);
renderBracelet();
return;
}
const rect =
bracelet.getBoundingClientRect();
const radius =
el.offsetWidth /
2;
let x =
e.clientX -
rect.left;
let y =
e.clientY -
rect.top;
x =
Math.max(
radius,
Math.min(
rect.width -
radius,
x
)
);
y =
Math.max(
radius,
Math.min(
rect.height -
radius,
y
)
);
saveHistory();
bead.x =
x;
bead.y =
y;
bead.manual =
true;
renderBracelet();
}
function cancel(){
if(!dragging) return;
cleanup();
renderBracelet();
}
function cleanup(){
dragging =
false;
pointerId =
null;
el.classList.remove(
'is-dragging'
);
document.removeEventListener(
'pointermove',
move
);
document.removeEventListener(
'pointerup',
up
);
document.removeEventListener(
'pointercancel',
cancel
);
}
el.addEventListener(
'pointerdown',
down
);
}
beadButtons.forEach(
function(button){
button.addEventListener(
'click',
function(){
if(
beads.length >=
maxBeads
){
showMessage(
'Maximum ' +
maxBeads +
' beads.'
);
return;
}
if(
!button.dataset.image
){
showMessage(
'Please add an image for this bead.'
);
return;
}
saveHistory();
beads.push({
name:
button.dataset.name ||
'Bead',
price:
Number(
button.dataset.price ||
0
),
image:
button.dataset.image,
uid:
Date.now() +
'-' +
Math.random(),
x:0,
y:0,
manual:false
});
renderBracelet();
}
);
}
);
clearBtn.addEventListener(
'click',
function(){
if(!beads.length){
return;
}
saveHistory();
beads = [];
renderBracelet();
}
);
undoBtn.addEventListener(
'click',
function(){
if(!history.length){
showMessage(
'Nothing to undo.'
);
return;
}
beads =
history.pop();
renderBracelet();
}
);
cartBtn.addEventListener(
'click',
async function(){
if(!beads.length){
showMessage(
'Please choose at least one bead.'
);
return;
}
if(!variantId){
showMessage(
'Please select your bracelet product.'
);
return;
}
const design =
beads.map(
function(bead,index){
return (
(index + 1) +
'. ' +
bead.name
);
}
).join(
' | '
);
const positionData =
beads.map(
function(bead,index){
return (
(index + 1) +
':' +
Math.round(bead.x) +
',' +
Math.round(bead.y)
);
}
).join(
' | '
);
cartBtn.disabled =
true;
cartBtn.textContent =
'Adding...';
try{
const response =
await fetch(
window.Shopify.routes.root +
'cart/add.js',
{
method:'POST',
headers:{
'Content-Type':
'application/json'
},
body:
JSON.stringify({
items:[
{
id:
Number(
variantId
),
quantity:1,
properties:{
'DIY Bracelet Design':
design,
'Bead Count':
String(
beads.length
),
'Bead Positions':
positionData,
'DIY Display Price':
money(
basePrice +
beads.reduce(
function(
sum,
bead
){
return (
sum +
Number(
bead.price ||
0
)
);
},
0
)
)
}
}
]
})
}
);
if(!response.ok){
throw new Error(
'Cart error'
);
}
cartBtn.textContent =
'Added ✓';
showMessage(
'Custom bracelet added to cart.'
);
setTimeout(
function(){
window.location.href =
window.Shopify.routes.root +
'cart';
},
500
);
}catch(error){
cartBtn.disabled =
false;
cartBtn.textContent =
'Add Custom Bracelet';
showMessage(
'Could not add to cart.'
);
}
}
);
window.addEventListener(
'resize',
function(){
const layout =
getLayout();
beads.forEach(
function(bead){
if(!bead.manual){
return;
}
bead.x =
Math.max(
30,
Math.min(
layout.rect.width -
30,
bead.x
)
);
bead.y =
Math.max(
30,
Math.min(
layout.rect.height -
30,
bead.y
)
);
}
);
renderBracelet();
}
);
renderBracelet();
})();