Skip to content

Instantly share code, notes, and snippets.

@dantetesta
Created September 23, 2024 00:13
Show Gist options
  • Save dantetesta/ac3cd0a685a7ac98e5e5dc13fd4a2c5d to your computer and use it in GitHub Desktop.
Save dantetesta/ac3cd0a685a7ac98e5e5dc13fd4a2c5d to your computer and use it in GitHub Desktop.
cropper
<!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">&times;</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