add new version

This commit is contained in:
2025-08-25 16:00:06 +03:00
parent 3247e7e32f
commit b3c65cb562

View File

@@ -9,7 +9,7 @@
let minZoom = 1; let minZoom = 1;
let restrictPosition = true; let restrictPosition = true;
let showGrid = false; let showGrid = false;
let croppedImage = null; // хранение вырезанного изображения let croppedImage = null;
let image: string; let image: string;
let incorrectImage: string; let incorrectImage: string;
@@ -18,7 +18,6 @@
let isDragging: boolean = false; let isDragging: boolean = false;
let isModalOpen: boolean = false; let isModalOpen: boolean = false;
// Проверка и загрузка изображения
async function validateAndLoadImage(file: File): Promise<void> { async function validateAndLoadImage(file: File): Promise<void> {
error = ""; error = "";
const img = new Image(); const img = new Image();
@@ -38,11 +37,10 @@
reader.readAsDataURL(file); reader.readAsDataURL(file);
} }
// Обработка Drag and Drop
function handleDrop(e: DragEvent): void { function handleDrop(e: DragEvent): void {
e.preventDefault(); e.preventDefault();
isDragging = false; isDragging = false;
const file = (e.dataTransfer as DataTransfer).files[0]; // Explicitly casting to DataTransfer const file = (e.dataTransfer as DataTransfer).files[0];
if (file && file.type.startsWith("image/")) { if (file && file.type.startsWith("image/")) {
validateAndLoadImage(file); validateAndLoadImage(file);
} }
@@ -62,35 +60,25 @@
let node = document.getElementById("result"); let node = document.getElementById("result");
// Убираем лишние стили
if (node) { if (node) {
domtoimage domtoimage
.toPng(node, { .toPng(node, {
style: { style: {
border: "none", // Убираем рамки border: "none",
padding: "0", // Убираем отступы padding: "0",
margin: "0", // Убираем маргины margin: "0",
outline: "none", // Убираем outline outline: "none",
}, },
}) })
.then((dataUrl: string) => { .then((dataUrl: string) => {
var link = document.createElement("a"); var link = document.createElement("a");
link.download = "avatar.png"; link.download = "avatar.png";
link.href = dataUrl; link.href = dataUrl;
link.click(); // Скачать изображение link.click();
}); });
} }
} }
const openModal = (): void => {
isModalOpen = true;
};
// Закрыть модальное окно
const closeModal = (): void => {
isModalOpen = false;
};
function cropImage(x: number, y: number, width: number, height: number) { function cropImage(x: number, y: number, width: number, height: number) {
const img = new Image(); const img = new Image();
img.src = incorrectImage; img.src = incorrectImage;
@@ -101,10 +89,8 @@
canvas.width = 512; canvas.width = 512;
canvas.height = 512; canvas.height = 512;
// Обрезаем изображение с помощью canvas
ctx.drawImage(img, x, y, width, height, 0, 0, 512, 512); ctx.drawImage(img, x, y, width, height, 0, 0, 512, 512);
// Получаем обрезанное изображение в формате base64
croppedImage = canvas.toDataURL("image/png"); croppedImage = canvas.toDataURL("image/png");
}; };
} }
@@ -115,7 +101,7 @@
}; };
function saveToMainImage() { function saveToMainImage() {
image = croppedImage; // Ссылка на обрезанное изображение image = croppedImage;
isModalOpen = false; isModalOpen = false;
} }
</script> </script>
@@ -140,16 +126,16 @@
<button <button
onclick={saveToMainImage} onclick={saveToMainImage}
class="px-6 py-3 bg-gradient-to-r from-purple-600 to-blue-600 text-white font-medium rounded-lg hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed" class="px-6 py-3 bg-gradient-to-r from-purple-600 to-blue-600 text-white font-medium rounded-lg hover:opacity-90 transition-opacity disabled:opacity-50 disabled:cursor-not-allowed mt-3"
> >
Сохранить Обрезать
</button> </button>
</div> </div>
</div> </div>
{:else} {:else}
<div class="bg-white rounded-xl shadow-lg p-6"> <div class="bg-white rounded-xl shadow-lg p-6">
<div <div
class="preview-container relative bg-gray-50 rounded-lg mb-4 overflow-hidden border-2 transition-colors h-[512px]" class="preview-container relative bg-gray-50 mb-4 overflow-hidden border-2 transition-colors h-[512px] w-[512px] rounded-full"
ondrop={handleDrop} ondrop={handleDrop}
ondragover={handleDragOver} ondragover={handleDragOver}
ondragleave={handleDragLeave} ondragleave={handleDragLeave}
@@ -179,22 +165,34 @@
<!-- Загруженное изображение --> <!-- Загруженное изображение -->
{#if image} {#if image}
<div id="result" class="relative"> <div id="result" class="w-full h-full">
<img src={image} class="object-cover" /> <svg viewBox="0 0 512 512" class="w-full h-full">
<!-- Текст --> <defs>
<clipPath id="circle-clip">
<circle cx="256" cy="256" r="256" />
</clipPath>
</defs>
<image href={image} width="512" height="512" clip-path="url(#circle-clip)" />
<!-- Текст -->
{#if text} {#if text}
<div <path
id="text-frame" id="text-path"
class="absolute bottom-0 left-0 right-0 py-5 bg-black/70 rounded-t-4xl" d="M 26,256 a 230,230 0 1,0 460,0 a 230,230 0 1,1 -460,0"
> fill="none"
<h1 />
class="text-center text-5xl font-bold text-transparent bg-clip-text bg-cover bg-right leading-17 tracking-tight" <linearGradient id="text-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
style="background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAADICAYAAACeXFkKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADs0lEQVR42u3WTU7DMBCA0RkOySU4HScMi4bW/06zYcF7EhKV09SeptKXn1/fR0RExhEREZkR8ft/RFRrERFZrh3Pax7vna2d/+drrbsu6/d098ij20+5p/Faeab2/vvzjs7UXbc9UzO/6Zmae+RgfuU9Fmcq97Q/U3NdDuZ34UzlLG+dafLsrM5UP1d3zrQ+b/nsDJ+r7kzXfivP++fN30q37/1vpbp/c6bjuXL+Zdavu/XXTofr5wcexe67e+Xo3lm/zv7e1edmrPd5DnG+/viCp2vVPt6byWoet2eSq31enEnz3Q6v3c0ki/kuZjb9Xqf7zM3Mms/NzTkiNzO78Kw/93FvJvNn+f2ZrJ/lizNpvtuPAAD+HQEAAAIAABAAAIAAAAAEAAAgAAAAAQAACAAAQAAAAAIAABAAAIAAAAAEAAAgAAAAAQAACAAAQAAAAAIAAAQAACAAAAABAAAIAABAAAAAAgAAEAAAgAAAAAQAACAAAAABAAAIAABAAAAAAgAAEAAAgAAAAAQAAAgAAEAAAAACAAAQAACAAAAABAAAIAAAAAEAAAgAAEAAAAACAAAQAACAAAAABAAAIAAAAAEAAAgAABAAAIAAAAAEAAAgAAAAAQAACAAAQAAAAAIAABAAAIAAAAAEAAAgAAAAAQAACAAAQAAAAAIAABAAACAAAAABAAAIAABAAAAAAgAAEAAAgAAAAAQAACAAAAABAAAIAABAAAAAAgAAEAAAgAAAAAQAACAAAAABAAACAAAQAACAAAAABAAAIAAAAAEAAAgAAEAAAAACAAAQAACAAAAABAAAIAAAAAEAAAgAAEAAAAACAAAEAAAgAAAAAQAACAAAQAAAAAIAABAAAIAAAAAEAAAgAAAAAQAACAAAQAAAAAIAABAAAIAAAAAEAAAIAABAAAAAAgAAEAAAgAAAAAQAACAAAAABAAAIAABAAAAAAgAAEAAAgAAAAAQAACAAAAABAAAIAAAQAACAAAAABAAAIAAAAAEAAAgAAEAAAAACAAAQAACAAAAABAAAIAAAAAEAAAgAAEAAAAACAAAQAAAgAAAAAQAACAAAQAAAAAIAABAAAIAAAAAEAAAgAAAAAQAACAAAQAAAAAIAABAAAIAAAAAEAAAgAAAAAQAAAgAAEAAAgAAAAAQAACAAAAABAAAIAABAAAAAAgAAEAAAgAAAAAQAACAAAAABAAAIAABAAAAAAgAABAAAIAAAAAEAAAgAAEAAAAACAAAQAACAAAAA/tYPVhsMy8Jj9qoAAAAASUVORK5CYII=');" <stop offset="0%" style="stop-color:rgb(124, 58, 237);stop-opacity:1" />
> <stop offset="100%" style="stop-color:rgb(37, 99, 235);stop-opacity:1" />
{text} </linearGradient>
</h1>
</div> <text class="circle-text-bg">
<textPath href="#text-path" startOffset="25%" text-anchor="middle">{text}</textPath>
</text>
<text class="circle-text">
<textPath href="#text-path" startOffset="25%" text-anchor="middle">{text}</textPath>
</text>
{/if} {/if}
</svg>
</div> </div>
{/if} {/if}
@@ -208,12 +206,10 @@
/> />
</div> </div>
<!-- Сообщение об ошибке -->
{#if error} {#if error}
<p class="text-red-500 text-sm mb-4 text-center">{error}</p> <p class="text-red-500 text-sm mb-4 text-center">{error}</p>
{/if} {/if}
<!-- Поле ввода текста -->
<div class="flex flex-col sm:flex-row gap-3 mb-4"> <div class="flex flex-col sm:flex-row gap-3 mb-4">
<input <input
type="text" type="text"
@@ -235,3 +231,27 @@
</div> </div>
{/if} {/if}
</div> </div>
<style>
.circle-text-bg {
fill: none;
stroke: rgb(0, 0, 0, 0.7);
stroke-width: 5px;
stroke-linejoin:round;
stroke-linecap:round;
paint-order: stroke;
font-size: 2.5rem;
font-weight: 700;
letter-spacing: 3px;
}
.circle-text {
fill: url(#text-gradient);
stroke: #000;
stroke-width: 1.5px;
paint-order: stroke;
letter-spacing: 3px;
font-size: 2.5rem;
font-weight: 700;
}
</style>