Tişört.Tasarım

v1.0
Tişört Rengi
Görsel Ekle

PNG, JPG, SVG, GIF, WEBP desteklenir. Görsel tasarım alanına eklenir.

Metin Ekle
Katmanlar
Dışa Aktar

Tasarım kılavuz çizgileri olmadan indirilir. Yüksek çözünürlük (2x) olarak kaydedilir.

Yardım

• Elemanları sürükleyerek taşıyabilirsin
Sarı noktadan tutarak yeniden boyutlandır
• Kırmızı × butonuyla sil
• Tişört rengi sol panelden değiştir

/** * Tişört Tasarım Aracı — tisort-tasarim.js * * Kullanım: * HTML sayfanıza şu script'leri ekleyin: * * * Sayfa yüklenince TisortTasarim.init() otomatik çalışır. */ const TisortTasarim = (() => { /* ── Sabit veriler ── */ const SHIRT_COLORS = [ { hex: '#ffffff', label: 'Beyaz' }, { hex: '#1a1a1a', label: 'Siyah' }, { hex: '#d63031', label: 'Kırmızı' }, { hex: '#0984e3', label: 'Mavi' }, { hex: '#00b894', label: 'Yeşil' }, { hex: '#fdcb6e', label: 'Sarı' }, { hex: '#6c5ce7', label: 'Mor' }, { hex: '#e17055', label: 'Turuncu' }, { hex: '#fd79a8', label: 'Pembe' }, { hex: '#74b9ff', label: 'Açık Mavi' }, { hex: '#55efc4', label: 'Turkuaz' }, { hex: '#636e72', label: 'Gri' }, ]; /* ── State ── */ let items = []; let selectedId = null; let idCounter = 0; let isBold = false; let isItalic = false; /* ── DOM referansları (init'te doldurulur) ── */ let area, colorGrid, layerList; let textInput, fontSizeInput, textColorInput, fontFamilyInput; let boldBtn, italicBtn; /* ──────────────────────────────────────────── INIT ──────────────────────────────────────────── */ function init() { area = document.getElementById('design-area'); colorGrid = document.getElementById('shirt-colors'); layerList = document.getElementById('layer-list'); textInput = document.getElementById('text-input'); fontSizeInput = document.getElementById('font-size'); textColorInput= document.getElementById('text-color'); fontFamilyInput = document.getElementById('font-family'); boldBtn = document.getElementById('bold-btn'); italicBtn = document.getElementById('italic-btn'); buildColorGrid(); bindUpload(); bindGlobalDeselect(); renderLayers(); } /* ──────────────────────────────────────────── SHIRT COLOR ──────────────────────────────────────────── */ function buildColorGrid() { SHIRT_COLORS.forEach((c, i) => { const btn = document.createElement('button'); btn.className = 'shirt-color-btn' + (i === 0 ? ' selected' : ''); btn.style.background = c.hex; if (c.hex === '#ffffff') btn.style.border = '2px solid rgba(255,255,255,0.2)'; btn.title = c.label; btn.dataset.hex = c.hex; btn.addEventListener('click', () => { document.querySelectorAll('.shirt-color-btn').forEach(b => b.classList.remove('selected')); btn.classList.add('selected'); setShirtColor(c.hex); }); colorGrid.appendChild(btn); }); } function setShirtColor(hex) { const shirtPath = document.getElementById('shirt-path'); const collarPath = document.getElementById('collar-path'); shirtPath.setAttribute('fill', hex); const dark = isDarkColor(hex); shirtPath.setAttribute('stroke', dark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.12)'); collarPath.setAttribute('fill', dark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.08)'); } function isDarkColor(hex) { const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return (r * 299 + g * 587 + b * 114) / 1000 < 128; } /* ──────────────────────────────────────────── GÖRSEL YÜKLEME ──────────────────────────────────────────── */ function bindUpload() { const uploadInput = document.getElementById('upload-input'); uploadInput.addEventListener('change', e => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = ev => addImage(ev.target.result, file.name); reader.readAsDataURL(file); e.target.value = ''; }); } function addImage(src, name) { const id = ++idCounter; const item = createItemWrapper(id); const img = document.createElement('img'); img.src = src; img.style.cssText = 'width:80px;height:auto;display:block;'; img.draggable = false; const del = makeDelBtn(id); const handle = makeResizeHandle(img, 'img'); item.querySelector('.item-inner').append(img, del, handle); area.appendChild(item); makeDraggable(item); selectItem(id); items.push({ id, el: item, type: 'img', name: name || 'Görsel' }); renderLayers(); } /* ──────────────────────────────────────────── METİN EKLEME ──────────────────────────────────────────── */ function addText() { const val = textInput.value.trim(); if (!val) return; const id = ++idCounter; const item = createItemWrapper(id); const span = document.createElement('span'); span.textContent = val; span.style.cssText = [ `font-size:${fontSizeInput.value}px`, `color:${textColorInput.value}`, `font-weight:${isBold ? 'bold' : 'normal'}`, `font-style:${isItalic ? 'italic' : 'normal'}`, `font-family:${fontFamilyInput.value}`, 'white-space:nowrap', 'display:block', 'line-height:1.2', ].join(';'); const del = makeDelBtn(id); const handle = makeResizeHandle(span, 'text'); item.querySelector('.item-inner').append(span, del, handle); area.appendChild(item); makeDraggable(item); selectItem(id); items.push({ id, el: item, type: 'text', name: val.substring(0, 16) }); renderLayers(); } /* ──────────────────────────────────────────── YARDIMCI: öğe wrapper oluştur ──────────────────────────────────────────── */ function createItemWrapper(id) { const item = document.createElement('div'); item.className = 'design-item'; item.dataset.id = id; item.style.cssText = 'left:10px;top:10px;position:absolute;'; const inner = document.createElement('div'); inner.className = 'item-inner'; item.appendChild(inner); return item; } /* ──────────────────────────────────────────── SİL BUTONU ──────────────────────────────────────────── */ function makeDelBtn(id) { const del = document.createElement('button'); del.className = 'del-btn'; del.textContent = '×'; del.onclick = e => { e.stopPropagation(); removeItem(id); }; return del; } /* ──────────────────────────────────────────── BOYUTLANDIRMA TUTAMACI ──────────────────────────────────────────── */ function makeResizeHandle(target, type) { const handle = document.createElement('div'); handle.className = 'resize-handle'; handle.addEventListener('mousedown', e => { e.stopPropagation(); e.preventDefault(); const startX = e.clientX; const startSize = type === 'img' ? target.offsetWidth : parseInt(target.style.fontSize); const onMove = mv => { const diff = mv.clientX - startX; if (type === 'img') { target.style.width = Math.max(20, startSize + diff) + 'px'; } else { target.style.fontSize = Math.max(8, Math.min(80, startSize + Math.round(diff / 3))) + 'px'; } }; const onUp = () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); }; window.addEventListener('mousemove', onMove); window.addEventListener('mouseup', onUp); }); return handle; } /* ──────────────────────────────────────────── SÜRÜKLE-BIRAK ──────────────────────────────────────────── */ function makeDraggable(el) { let sX, sY, sL, sT; const startDrag = (cx, cy) => { selectItem(parseInt(el.dataset.id)); sX = cx; sY = cy; sL = parseInt(el.style.left) || 0; sT = parseInt(el.style.top) || 0; }; const moveDrag = (cx, cy) => { let nx = sL + cx - sX; let ny = sT + cy - sY; const aw = area.clientWidth, ah = area.clientHeight; const ew = el.offsetWidth, eh = el.offsetHeight; nx = Math.max(0, Math.min(aw - ew, nx)); ny = Math.max(0, Math.min(ah - eh, ny)); el.style.left = nx + 'px'; el.style.top = ny + 'px'; }; /* Mouse */ el.addEventListener('mousedown', e => { if (e.target.classList.contains('del-btn') || e.target.classList.contains('resize-handle')) return; e.preventDefault(); startDrag(e.clientX, e.clientY); const onMove = mv => moveDrag(mv.clientX, mv.clientY); const onUp = () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); }; window.addEventListener('mousemove', onMove); window.addEventListener('mouseup', onUp); }); /* Touch */ el.addEventListener('touchstart', e => { if (e.target.classList.contains('del-btn') || e.target.classList.contains('resize-handle')) return; const t = e.touches[0]; startDrag(t.clientX, t.clientY); const onMove = mv => { const t2 = mv.touches[0]; moveDrag(t2.clientX, t2.clientY); }; const onUp = () => { window.removeEventListener('touchmove', onMove); window.removeEventListener('touchend', onUp); }; window.addEventListener('touchmove', onMove, { passive: true }); window.addEventListener('touchend', onUp); }, { passive: true }); } /* ──────────────────────────────────────────── SEÇİM / SİLME / TEMİZLEME ──────────────────────────────────────────── */ function selectItem(id) { selectedId = id; document.querySelectorAll('.design-item').forEach(el => el.classList.remove('selected')); const found = items.find(i => i.id === id); if (found) found.el.classList.add('selected'); renderLayers(); } function removeItem(id) { const idx = items.findIndex(i => i.id === id); if (idx >= 0) { items[idx].el.remove(); items.splice(idx, 1); } if (selectedId === id) selectedId = null; renderLayers(); } function clearAll() { if (!items.length) return; if (!confirm('Tüm tasarım öğeleri silinecek. Emin misin?')) return; items.forEach(i => i.el.remove()); items = []; selectedId = null; renderLayers(); } function bindGlobalDeselect() { document.addEventListener('click', e => { if (!area.contains(e.target)) { document.querySelectorAll('.design-item').forEach(el => el.classList.remove('selected')); selectedId = null; renderLayers(); } }); } /* ──────────────────────────────────────────── KATMAN LİSTESİ ──────────────────────────────────────────── */ function renderLayers() { if (!items.length) { layerList.innerHTML = '
Henüz öğe yok
'; return; } layerList.innerHTML = ''; [...items].reverse().forEach(item => { const div = document.createElement('div'); div.className = 'layer-item' + (item.id === selectedId ? ' active' : ''); div.innerHTML = ` ${item.type === 'img' ? '🖼' : 'T'} ${escHtml(item.name)} `; div.addEventListener('click', () => selectItem(item.id)); layerList.appendChild(div); }); } function escHtml(s) { return s.replace(/&/g, '&').replace(//g, '>'); } /* ──────────────────────────────────────────── KALIN / İTALİK ──────────────────────────────────────────── */ function toggleBold() { isBold = !isBold; boldBtn.classList.toggle('on', isBold); } function toggleItalic() { isItalic = !isItalic; italicBtn.classList.toggle('on', isItalic); } /* ──────────────────────────────────────────── DIŞA AKTARMA ──────────────────────────────────────────── */ function doExport(type) { if (typeof html2canvas === 'undefined') { alert('html2canvas kütüphanesi yüklü değil!'); return; } const canvas = document.getElementById('tshirt-canvas'); area.style.border = 'none'; document.querySelectorAll('.del-btn,.resize-handle').forEach(e => e.style.display = 'none'); html2canvas(canvas, { backgroundColor: null, scale: 2, useCORS: true }).then(c => { area.style.border = '1.5px dashed rgba(232,255,71,0.35)'; document.querySelectorAll('.design-item.selected .del-btn, .design-item.selected .resize-handle') .forEach(e => e.style.display = 'block'); const a = document.createElement('a'); if (type === 'jpeg') { a.download = 'tisort-tasarim.jpg'; a.href = c.toDataURL('image/jpeg', 0.95); } else { a.download = 'tisort-tasarim.png'; a.href = c.toDataURL('image/png'); } a.click(); }); } function exportPNG() { doExport('png'); } function exportJPEG() { doExport('jpeg'); } /* ──────────────────────────────────────────── AUTO-INIT ──────────────────────────────────────────── */ document.addEventListener('DOMContentLoaded', init); /* ── Public API ── */ return { init, addText, addImage, removeItem, clearAll, toggleBold, toggleItalic, exportPNG, exportJPEG, setShirtColor, }; })();
Yeni sezon ürünler
150 TL üzeri ücretsiz kargo
Yeni sezon ürünler
150 TL üzeri ücretsiz kargo

Sıkça Sorulan Sorular

Hangi Beden Bana Uygun Olur?
Hangi Ödeme Yöntemlerini Kullanabilirim?