class ClothesSelector extends HTMLElement {
constructor() {
super();
this.selectionPoints = [];
this.selectionMode = false;
this.segmentationActive = false;
this.selfieSegmentation = null;
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
this.setupEventListeners();
}
render() {
this.shadowRoot.innerHTML = `
`;
}
async setupSegmentation() {
this.selfieSegmentation = new SelfieSegmentation({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${file}`;
}
});
this.selfieSegmentation.setOptions({
modelSelection: 1,
selfieMode: false
});
await this.selfieSegmentation.initialize();
}
async processSegmentation() {
if (!this.selfieSegmentation || !this.shadowRoot.getElementById('previewImage').complete) return;
const img = this.shadowRoot.getElementById('previewImage');
const canvas = this.shadowRoot.getElementById('selectionCanvas');
const ctx = canvas.getContext('2d');
try {
const result = await this.selfieSegmentation.send({image: img});
const mask = result.segmentationMask;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(mask, 0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-in';
ctx.fillStyle = 'rgba(59, 130, 246, 0.5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-over';
} catch (error) {
console.error('Segmentation error:', error);
}
}
setupEventListeners() {
const img = this.shadowRoot.getElementById('previewImage');
const canvas = this.shadowRoot.getElementById('selectionCanvas');
const ctx = canvas.getContext('2d');
const selectBtn = this.shadowRoot.getElementById('selectBtn');
const clearBtn = this.shadowRoot.getElementById('clearBtn');
const downloadBtn = this.shadowRoot.getElementById('downloadBtn');
selectBtn.addEventListener('click', async () => {
if (!this.selfieSegmentation) {
await this.setupSegmentation();
}
this.selectionMode = true;
this.segmentationActive = true;
this.selectionPoints = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
img.style.cursor = 'crosshair';
if (img.complete) {
await this.processSegmentation();
}
});
clearBtn.addEventListener('click', () => {
this.selectionPoints = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
img.style.cursor = 'default';
this.selectionMode = false;
this.segmentationActive = false;
});
downloadBtn.addEventListener('click', () => {
if (this.selectionPoints.length > 0) {
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = img.naturalWidth;
tempCanvas.height = img.naturalHeight;
tempCtx.drawImage(img, 0, 0);
tempCtx.globalCompositeOperation = 'destination-in';
tempCtx.fillStyle = 'black';
tempCtx.beginPath();
tempCtx.moveTo(this.selectionPoints[0].x, this.selectionPoints[0].y);
for (let i = 1; i < this.selectionPoints.length; i++) {
tempCtx.lineTo(this.selectionPoints[i].x, this.selectionPoints[i].y);
}
tempCtx.closePath();
tempCtx.fill();
const link = document.createElement('a');
link.download = 'selected-clothing.png';
link.href = tempCanvas.toDataURL('image/png');
link.click();
}
});
img.addEventListener('click', (e) => {
if (!this.selectionMode) return;
const rect = img.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.selectionPoints.push({x, y});
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = '#3B82F6';
ctx.lineWidth = 2;
ctx.fillStyle = 'rgba(59, 130, 246, 0.2)';
if (this.selectionPoints.length > 0) {
ctx.beginPath();
ctx.moveTo(this.selectionPoints[0].x, this.selectionPoints[0].y);
for (let i = 1; i < this.selectionPoints.length; i++) {
ctx.lineTo(this.selectionPoints[i].x, this.selectionPoints[i].y);
}
if (this.selectionPoints.length > 2) {
ctx.closePath();
ctx.fill();
}
ctx.stroke();
}
});
img.addEventListener('load', async () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
if (this.segmentationActive) {
await this.processSegmentation();
}
});
}
setImage(src) {
const img = this.shadowRoot.getElementById('previewImage');
img.src = src;
}
}
customElements.define('clothes-selector', ClothesSelector);