Created
September 23, 2024 00:13
-
-
Save dantetesta/ac3cd0a685a7ac98e5e5dc13fd4a2c5d to your computer and use it in GitHub Desktop.
cropper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="pt-BR"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Editar Foto de Perfil</title> | |
<!-- Cropper.js CSS --> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css"> | |
<!-- Font Awesome para ícones --> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> | |
<style> | |
/* Variáveis de Cores */ | |
:root { | |
--primary-color: #4CAF50; | |
--primary-hover: #45a049; | |
--secondary-color: #f1f1f1; | |
--secondary-hover: #ddd; | |
--button-color: #ffffff; | |
--button-hover: #f0f0f0; | |
--button-active: #e0e0e0; | |
--modal-bg: rgba(0, 0, 0, 0.5); | |
--modal-content-bg: #ffffff; | |
} | |
/* Estilos Gerais */ | |
body { | |
font-family: 'Arial', sans-serif; | |
margin: 0; | |
padding: 0; | |
background-color: #f0f2f5; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
min-height: 100vh; | |
} | |
.profile-container { | |
background-color: var(--button-color); | |
border-radius: 12px; | |
box-shadow: 0 4px 20px rgba(0,0,0,0.1); | |
padding: 30px; | |
text-align: center; | |
max-width: 450px; | |
width: 90%; | |
} | |
.avatar-container { | |
position: relative; | |
width: 150px; /* Ajustado para 150px */ | |
height: 150px; /* Ajustado para 150px */ | |
margin: 0 auto 25px; | |
} | |
.avatar { | |
width: 100%; | |
height: 100%; | |
border-radius: 50%; | |
object-fit: cover; | |
border: 4px solid var(--button-color); | |
box-shadow: 0 4px 12px rgba(0,0,0,0.1); | |
transition: border 0.3s; | |
} | |
.avatar-container:hover .avatar { | |
border: 4px solid var(--primary-color); | |
} | |
.edit-button { | |
position: absolute; | |
bottom: 0; | |
right: 0; | |
background-color: var(--primary-color); | |
color: var(--button-color); | |
border: none; | |
border-radius: 50%; | |
width: 45px; | |
height: 45px; | |
font-size: 20px; | |
cursor: pointer; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
transition: background-color 0.3s, transform 0.2s; | |
} | |
.edit-button:hover { | |
background-color: var(--primary-hover); | |
transform: scale(1.05); | |
} | |
.edit-button:active { | |
transform: scale(0.95); | |
} | |
.modal { | |
display: none; | |
position: fixed; | |
z-index: 1000; | |
left: 0; | |
top: 0; | |
width: 100%; | |
height: 100%; | |
overflow-y: auto; | |
background-color: var(--modal-bg); | |
padding: 20px; | |
box-sizing: border-box; | |
} | |
.modal-content { | |
background-color: var(--modal-content-bg); | |
margin: auto; | |
padding: 25px; | |
border-radius: 12px; | |
max-width: 700px; | |
width: 100%; | |
box-sizing: border-box; | |
box-shadow: 0 4px 20px rgba(0,0,0,0.2); | |
position: relative; | |
} | |
.close { | |
color: #aaa; | |
position: absolute; | |
top: 15px; | |
right: 20px; | |
font-size: 30px; | |
font-weight: bold; | |
cursor: pointer; | |
transition: color 0.3s; | |
} | |
.close:hover { | |
color: #000; | |
} | |
#image-container { | |
width: 100%; | |
max-height: 400px; | |
margin: 20px 0; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
#image-container img { | |
max-width: 100%; | |
max-height: 400px; | |
display: block; | |
border-radius: 8px; | |
} | |
#actions, #extra-controls { | |
margin-top: 25px; | |
display: grid; | |
gap: 12px; | |
} | |
/* Controles Extra (Zoom, Flip, Rotate) */ | |
#extra-controls { | |
grid-template-columns: repeat(auto-fit, minmax(50px, 1fr)); | |
} | |
/* Controles de Relação de Aspecto e Salvar */ | |
#actions { | |
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); | |
} | |
.btn { | |
padding: 12px; | |
border: none; | |
border-radius: 8px; | |
cursor: pointer; | |
font-size: 16px; | |
transition: background-color 0.3s, transform 0.2s; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
background-color: var(--secondary-color); | |
color: #333; | |
box-shadow: 0 2px 6px rgba(0,0,0,0.1); | |
} | |
.btn:hover { | |
background-color: var(--secondary-hover); | |
transform: translateY(-2px); | |
} | |
.btn:active { | |
transform: translateY(0px); | |
box-shadow: 0 1px 3px rgba(0,0,0,0.1); | |
} | |
.btn-primary { | |
background-color: var(--primary-color); | |
color: var(--button-color); | |
box-shadow: 0 2px 6px rgba(0,0,0,0.15); | |
} | |
.btn-primary:hover { | |
background-color: var(--primary-hover); | |
} | |
/* Responsividade */ | |
@media (max-width: 1024px) and (min-width: 769px) { | |
/* Tablet */ | |
#extra-controls { | |
grid-template-columns: repeat(6, 1fr); /* 6 colunas */ | |
} | |
#actions { | |
grid-template-columns: repeat(3, 1fr); /* 3 colunas */ | |
} | |
#crop-button { | |
grid-column: span 3; /* Ocupa 100% */ | |
} | |
/* Aspect Ratio Buttons */ | |
.aspect-ratio-button { | |
justify-content: center; | |
text-align: center; | |
font-weight: bold; | |
} | |
} | |
@media (max-width: 768px) { | |
/* Mobile */ | |
#extra-controls { | |
grid-template-columns: repeat(6, 1fr); /* 6 colunas */ | |
} | |
#actions { | |
grid-template-columns: repeat(3, 1fr); /* 3 colunas */ | |
} | |
#crop-button { | |
grid-column: span 3; /* Ocupa 100% */ | |
} | |
/* Ocultar textos nos botões de comandos (Zoom, Flip, Rotate) */ | |
.btn .btn-text { | |
display: none; | |
} | |
/* Aspect Ratio Buttons */ | |
.aspect-ratio-button { | |
justify-content: center; | |
text-align: center; | |
font-weight: bold; | |
} | |
} | |
@media (min-width: 1025px) { | |
/* Desktop */ | |
#extra-controls { | |
grid-template-columns: repeat(6, 1fr); /* 6 colunas */ | |
} | |
#actions { | |
grid-template-columns: repeat(3, 1fr); /* 3 colunas */ | |
} | |
#crop-button { | |
grid-column: span 3; /* Ocupa 100% */ | |
} | |
/* Aspect Ratio Buttons */ | |
.aspect-ratio-button { | |
justify-content: center; | |
text-align: center; | |
font-weight: bold; | |
} | |
} | |
/* Botão de Selecionar Imagem com Label */ | |
#upload-btn { | |
width: 100%; | |
justify-content: center; | |
background-color: var(--secondary-color); | |
color: #333; | |
display: flex; | |
align-items: center; | |
} | |
#upload-btn:hover { | |
background-color: var(--secondary-hover); | |
} | |
/* Espaçamento entre Ícone e Texto no Botão Selecionar Imagem */ | |
#upload-btn .btn-text { | |
margin-left: 8px; /* Adicionado espaço */ | |
} | |
</style> | |
</head> | |
<body> | |
<div class="profile-container"> | |
<div class="avatar-container"> | |
<img src="https://via.placeholder.com/150" alt="Avatar" class="avatar" id="profile-avatar"> <!-- Ajustado para 150x150 --> | |
<button class="edit-button" id="edit-avatar-btn" title="Editar Avatar"> | |
<i class="fas fa-pencil-alt"></i> | |
</button> | |
</div> | |
<h2>Nome do Usuário</h2> | |
</div> | |
<div id="avatar-modal" class="modal"> | |
<div class="modal-content"> | |
<span class="close" title="Fechar">×</span> | |
<h2>Editar Foto de Perfil</h2> | |
<input type="file" id="file-input" accept="image/*" style="display: none;"> | |
<button class="btn btn-secondary" id="upload-btn" title="Selecionar Imagem"> | |
<i class="fas fa-upload"></i> | |
<span class="btn-text">Selecionar Imagem</span> <!-- Espaço adicionado --> | |
</button> | |
<div id="image-container"></div> | |
<div id="extra-controls" style="display: none;"> | |
<button class="btn btn-secondary" id="zoom-in" title="Zoom In"> | |
<i class="fas fa-search-plus"></i> | |
</button> | |
<button class="btn btn-secondary" id="zoom-out" title="Zoom Out"> | |
<i class="fas fa-search-minus"></i> | |
</button> | |
<button class="btn btn-secondary" id="flip-horizontal" title="Flip Horizontal"> | |
<i class="fas fa-arrows-alt-h"></i> | |
</button> | |
<button class="btn btn-secondary" id="flip-vertical" title="Flip Vertical"> | |
<i class="fas fa-arrows-alt-v"></i> | |
</button> | |
<button class="btn btn-secondary" id="rotate-left" title="Rotacionar -15°"> | |
<i class="fas fa-undo"></i> | |
</button> | |
<button class="btn btn-secondary" id="rotate-right" title="Rotacionar +15°"> | |
<i class="fas fa-redo"></i> | |
</button> | |
</div> | |
<div id="actions" style="display: none;"> | |
<button class="btn btn-secondary aspect-ratio-button" data-ratio="1:1" title="Relação de Aspecto 1:1"> | |
1:1 | |
</button> | |
<button class="btn btn-secondary aspect-ratio-button" data-ratio="1:2" title="Relação de Aspecto 1:2"> | |
1:2 | |
</button> | |
<button class="btn btn-secondary aspect-ratio-button" data-ratio="2:1" title="Relação de Aspecto 2:1"> | |
2:1 | |
</button> | |
<button class="btn btn-primary" id="crop-button" title="Salvar"> | |
Salvar | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Cropper.js JS --> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script> | |
<script> | |
document.addEventListener('DOMContentLoaded', function () { | |
const modal = document.getElementById('avatar-modal'); | |
const editBtn = document.getElementById('edit-avatar-btn'); | |
const closeBtn = document.getElementsByClassName('close')[0]; | |
const fileInput = document.getElementById('file-input'); | |
const uploadBtn = document.getElementById('upload-btn'); | |
const imageContainer = document.getElementById('image-container'); | |
const actions = document.getElementById('actions'); | |
const extraControls = document.getElementById('extra-controls'); | |
const cropButton = document.getElementById('crop-button'); | |
const aspectRatioButtons = document.querySelectorAll('.aspect-ratio-button'); | |
const profileAvatar = document.getElementById('profile-avatar'); | |
let cropper; | |
let originalImage = null; // Variável para armazenar a imagem original | |
// Função para abrir o modal | |
editBtn.onclick = function() { | |
modal.style.display = "block"; | |
initializeCropper(); | |
} | |
// Função para fechar o modal | |
closeBtn.onclick = function() { | |
closeModal(); | |
} | |
// Fechar modal ao clicar fora do conteúdo | |
window.onclick = function(event) { | |
if (event.target == modal) { | |
closeModal(); | |
} | |
} | |
// Acionar o input de arquivo ao clicar no botão de upload | |
uploadBtn.onclick = function() { | |
fileInput.click(); | |
} | |
// Carregar a imagem selecionada | |
fileInput.addEventListener('change', function (e) { | |
const file = e.target.files[0]; | |
if (!file) return; | |
const reader = new FileReader(); | |
reader.onload = function (e) { | |
if (cropper) { | |
cropper.destroy(); | |
} | |
const img = document.createElement('img'); | |
img.id = 'image'; | |
img.src = e.target.result; | |
imageContainer.innerHTML = ''; | |
imageContainer.appendChild(img); | |
cropper = new Cropper(img, { | |
aspectRatio: 1, | |
viewMode: 1, | |
dragMode: 'move', | |
movable: true, | |
zoomable: true, | |
rotatable: true, | |
scalable: true, | |
responsive: true, | |
background: false, | |
autoCropArea: 1, | |
modal: true, | |
guides: true, | |
center: true, | |
highlight: true, | |
cropBoxMovable: true, | |
cropBoxResizable: true, | |
}); | |
actions.style.display = 'grid'; | |
extraControls.style.display = 'grid'; | |
originalImage = e.target.result; // Armazenar a imagem original | |
}; | |
reader.readAsDataURL(file); | |
}); | |
// Função para inicializar o cropper com a imagem atual | |
function initializeCropper() { | |
const currentSrc = profileAvatar.src; | |
if (originalImage) { | |
if (cropper) { | |
cropper.destroy(); | |
} | |
const img = document.createElement('img'); | |
img.id = 'image'; | |
img.src = originalImage; | |
imageContainer.innerHTML = ''; | |
imageContainer.appendChild(img); | |
cropper = new Cropper(img, { | |
aspectRatio: 1, | |
viewMode: 1, | |
dragMode: 'move', | |
movable: true, | |
zoomable: true, | |
rotatable: true, | |
scalable: true, | |
responsive: true, | |
background: false, | |
autoCropArea: 1, | |
modal: true, | |
guides: true, | |
center: true, | |
highlight: true, | |
cropBoxMovable: true, | |
cropBoxResizable: true, | |
}); | |
actions.style.display = 'grid'; | |
extraControls.style.display = 'grid'; | |
} else if (currentSrc && currentSrc !== 'https://via.placeholder.com/150') { // Ajustado para 150x150 | |
if (cropper) { | |
cropper.destroy(); | |
} | |
const img = document.createElement('img'); | |
img.id = 'image'; | |
img.src = currentSrc; | |
imageContainer.innerHTML = ''; | |
imageContainer.appendChild(img); | |
cropper = new Cropper(img, { | |
aspectRatio: 1, | |
viewMode: 1, | |
dragMode: 'move', | |
movable: true, | |
zoomable: true, | |
rotatable: true, | |
scalable: true, | |
responsive: true, | |
background: false, | |
autoCropArea: 1, | |
modal: true, | |
guides: true, | |
center: true, | |
highlight: true, | |
cropBoxMovable: true, | |
cropBoxResizable: true, | |
}); | |
actions.style.display = 'grid'; | |
extraControls.style.display = 'grid'; | |
} else { | |
// Se não há imagem atual, limpar o container | |
imageContainer.innerHTML = ''; | |
actions.style.display = 'none'; | |
extraControls.style.display = 'none'; | |
} | |
} | |
// Função para fechar o modal e limpar o cropper | |
function closeModal() { | |
modal.style.display = "none"; | |
if (cropper) { | |
cropper.destroy(); | |
cropper = null; | |
} | |
imageContainer.innerHTML = ''; | |
actions.style.display = 'none'; | |
extraControls.style.display = 'none'; | |
fileInput.value = ''; | |
} | |
// Botões de relação de aspecto | |
aspectRatioButtons.forEach(function(button) { | |
button.addEventListener('click', function() { | |
const ratio = this.getAttribute('data-ratio').split(':'); | |
const aspectRatio = parseInt(ratio[0]) / parseInt(ratio[1]); | |
cropper.setAspectRatio(aspectRatio); | |
}); | |
}); | |
// Botões de zoom | |
document.getElementById('zoom-in').addEventListener('click', function() { | |
cropper.zoom(0.1); | |
}); | |
document.getElementById('zoom-out').addEventListener('click', function() { | |
cropper.zoom(-0.1); | |
}); | |
// Botões de flip horizontal e vertical | |
document.getElementById('flip-horizontal').addEventListener('click', function() { | |
const currentScaleX = cropper.getData().scaleX || 1; | |
cropper.scaleX(currentScaleX === 1 ? -1 : 1); | |
}); | |
document.getElementById('flip-vertical').addEventListener('click', function() { | |
const currentScaleY = cropper.getData().scaleY || 1; | |
cropper.scaleY(currentScaleY === 1 ? -1 : 1); | |
}); | |
// Botões de rotação | |
document.getElementById('rotate-left').addEventListener('click', function() { | |
cropper.rotate(-15); | |
}); | |
document.getElementById('rotate-right').addEventListener('click', function() { | |
cropper.rotate(15); | |
}); | |
// Botão de salvar (crop) | |
cropButton.addEventListener('click', function () { | |
if (!cropper) return; | |
const croppedCanvas = cropper.getCroppedCanvas({ | |
width: 300, | |
height: 300, | |
imageSmoothingQuality: 'high', | |
}); | |
profileAvatar.src = croppedCanvas.toDataURL('image/jpeg'); | |
closeModal(); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment