서버 점검 안내

dsclub은 서비스의 안정성과 성능 향상을 위해
매일 04시 30분에 정기 점검이 진행됩니다.

점검 시간: 오전 4시 30분 ~ 4시 35분

해당 시간 동안 일시적으로 서비스에 접속이 불가능하오니, 양해 부탁드립니다.

(Twave) 프로필 수정 기능 추가 > 코딩 스토리

(Twave) 프로필 수정 기능 추가

페이지 정보

작성자 회원이미지 tak2 (211.♡.94.136) 작성일 24-11-02 19:54 조회 134 댓글 1

본문

기존에는 기기 자체의 사진 편집기를 통해 사진 편집 후 프로필 이미지를 업로드 해야 프로필 이미지를 꾸밀 수 있었는데 이 점을 보완하여 프로필 사진 확대/축소/회전 기능을 기본 탑재하였습니다.

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 입니다 )

좋아요0 이 글을 좋아요하셨습니다
url 복사 카카오톡 공유 라인 공유 페이스북 공유 트위터 공유

tak2님의 댓글

회원이미지 tak2 아이피 (192.♡.0.1) 작성일

댓글알람 테스뜨

전체 282건
게시물 검색

접속자집계

오늘
661
어제
1,491
최대
4,271
전체
321,465