(Twave) 프로필 수정 기능 추가
본문
기존에는 기기 자체의 사진 편집기를 통해 사진 편집 후 프로필 이미지를 업로드 해야 프로필 이미지를 꾸밀 수 있었는데 이 점을 보완하여 프로필 사진 확대/축소/회전 기능을 기본 탑재하였습니다.
profile_form.skin.php에 아래의 코드를 원하는 위치에 추가하시면 됩니다.
<style>
/* 이미지 편집 모달 스타일 */
.image-editor-modal {
display: none;
position: fixed;
z-index: 1000;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.85);
align-items: center;
justify-content: center;
font-family: 'Arial', sans-serif;
}
.image-editor-content {
background-color: #ffffff;
padding: 10px;
border-radius: 20px;
max-width: 90%;
text-align: center;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
width: 90%;
max-width: 360px;
}
.editor-canvas {
border-radius: 8px;
border: 1px solid #e6e6e6;
width: 100%;
height: auto;
margin-bottom: 10px;
}
/* 버튼 스타일 */
.image-editor-buttons {
display: flex;
justify-content: space-around;
margin-top: 10px;
}
.image-editor-buttons button {
background-color: #2792fb;
color: #fff;
border: none;
border-radius: 20px;
padding: 8px 12px;
cursor: pointer;
font-size: 13px;
transition: background-color 0.3s ease;
flex: 1;
margin: 0 5px;
}
.image-editor-buttons button:hover {
background-color: #2792fb;
}
/* 취소 버튼 별도 스타일 */
#cancelEdit {
background-color: #dbdbdb;
color: #262626;
}
#cancelEdit:hover {
background-color: #c1c1c1;
}
</style>
<!-- 이미지 편집 모달 구조 -->
<div class="image-editor-modal" id="imageEditorModal">
<div class="image-editor-content">
<canvas id="editorCanvas" class="editor-canvas"></canvas>
<div class="image-editor-buttons">
<button type="button" id="rotateLeft">회전</button>
<button type="button" id="applyChanges">적용</button>
<button type="button" id="cancelEdit">취소</button>
</div>
</div>
</div>
<script>
const imageEditorModal = document.getElementById('imageEditorModal');
const editorCanvas = document.getElementById('editorCanvas');
const ctx = editorCanvas.getContext('2d');
let scale = 1;
let rotation = 0;
let img = new Image();
let offsetX = 0;
let offsetY = 0;
let initialDistance = null;
const canvasSize = 300; // 1:1 비율을 위한 고정 크기
const snapThreshold = 20; // 중앙으로 스냅되는 거리 설정
document.getElementById('reg_mb_img').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
imageEditorModal.style.display = 'flex';
document.body.style.overflow = 'hidden'; // 모달 열릴 때 스크롤 잠금
img.src = e.target.result;
img.onload = function() {
editorCanvas.width = canvasSize;
editorCanvas.height = canvasSize;
applyTransformations();
};
};
reader.readAsDataURL(file);
}
});
function applyTransformations() {
ctx.clearRect(0, 0, editorCanvas.width, editorCanvas.height);
ctx.save();
ctx.translate(editorCanvas.width / 2 + offsetX, editorCanvas.height / 2 + offsetY);
ctx.scale(scale, scale);
ctx.rotate((rotation * Math.PI) / 180);
const imgAspect = img.width / img.height;
const canvasAspect = editorCanvas.width / editorCanvas.height;
let renderWidth, renderHeight;
if (imgAspect > canvasAspect) {
renderHeight = editorCanvas.height;
renderWidth = img.width * (renderHeight / img.height);
} else {
renderWidth = editorCanvas.width;
renderHeight = img.height * (renderWidth / img.width);
}
ctx.drawImage(img, -renderWidth / 2, -renderHeight / 2, renderWidth, renderHeight);
ctx.restore();
}
function snapToCenter() {
if (Math.abs(offsetX) < snapThreshold) {
offsetX = 0;
}
if (Math.abs(offsetY) < snapThreshold) {
offsetY = 0;
}
}
// 핀치 줌 및 드래그 기능
editorCanvas.addEventListener('touchstart', function(e) {
e.preventDefault(); // 기본 동작 방지
if (e.touches.length === 1) { // 드래그 시작
lastX = e.touches[0].clientX;
lastY = e.touches[0].clientY;
} else if (e.touches.length === 2) { // 핀치 줌 시작
initialDistance = getDistance(e.touches[0], e.touches[1]);
}
});
editorCanvas.addEventListener('touchmove', function(e) {
e.preventDefault(); // 기본 동작 방지
if (e.touches.length === 1) { // 드래그 이동
const deltaX = e.touches[0].clientX - lastX;
const deltaY = e.touches[0].clientY - lastY;
lastX = e.touches[0].clientX;
lastY = e.touches[0].clientY;
offsetX += deltaX;
offsetY += deltaY;
snapToCenter(); // 이동할 때마다 자석 기능 적용
applyTransformations();
} else if (e.touches.length === 2) { // 핀치 줌
const newDistance = getDistance(e.touches[0], e.touches[1]);
if (initialDistance) {
const scaleChange = newDistance / initialDistance;
scale = Math.max(0.5, Math.min(3, scale * scaleChange)); // 0.5 ~ 3배율 사이로 제한
initialDistance = newDistance;
applyTransformations();
}
}
});
editorCanvas.addEventListener('touchend', function(e) {
e.preventDefault();
if (e.touches.length === 0) { // 터치 종료
initialDistance = null;
snapToCenter(); // 터치가 끝날 때도 자석 기능 적용
applyTransformations();
}
});
function getDistance(touch1, touch2) {
const dx = touch2.clientX - touch1.clientX;
const dy = touch2.clientY - touch1.clientY;
return Math.sqrt(dx * dx + dy * dy);
}
// 모달 외부의 터치 및 스크롤 방지
document.addEventListener('touchmove', function(e) {
if (imageEditorModal.style.display === 'flex') {
e.preventDefault(); // 기본 동작 및 외부 스크롤 방지
}
}, { passive: false });
// 회전 버튼
document.getElementById('rotateLeft').addEventListener('click', function() {
rotation += 90;
applyTransformations();
});
// 적용 버튼 클릭 시 동작
document.getElementById('applyChanges').addEventListener('click', function(event) {
event.preventDefault();
editorCanvas.toBlob(function(blob) {
const fileInput = document.getElementById('reg_mb_img');
const file = new File([blob], 'edited_profile.png', { type: 'image/png' });
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
document.getElementById('profileImage').src = editorCanvas.toDataURL();
imageEditorModal.style.display = 'none';
document.body.style.overflow = ''; // 모달 닫힐 때 스크롤 복구
});
});
document.getElementById('cancelEdit').addEventListener('click', function(event) {
event.preventDefault();
imageEditorModal.style.display = 'none';
document.body.style.overflow = ''; // 모달 닫힐 때 스크롤 복구
});
</script>
( 현재 dsclub에서 사용중인 테마의 버전은 TwaveCv2 - Twave 커스텀 버전2 입니다 )
tak2님의 댓글
tak2 아이피 (192.♡.0.1) 작성일댓글알람 테스뜨