[React] 마인드맵 작업일지 (0530~)

Franklee·2023년 5월 30일
0

Project

목록 보기
2/2

0530

엘리먼트 최적화.

moveSlice를 사용하여 이동시에는 해당 리덕스를 갱신하는 방식으로 ondragStart시에 리덕스에 이동시킬 엘리먼트를 저장하고 ondrag에는 해당 리덕스를 지속적으로 갱신시키고, ondragEnd에 해당 리덕스의 엘리먼트 요소를 전체 eleSlice에 업데이트 시킴으로서 line.tsx의 계산 및 dragSection의 엘리먼트의 성능을 최적화를 하게 되었다
=> 이로서 엘리먼트가 많아질수록 drag시에 상당한 프레임드랍이 발생되었지만, 수정 이후로는 아무리 엘리먼트를 많이 추가해도 엘리먼트 이동시에 프레임드랍이 발생하지 않는것을 확인했다.

info / list 작업

list에 엘리먼트 구성 순서에 맞게 나열시키고 리스트의 해당 엘리먼트 hover시 dragSection의 엘리먼트의 배경변화로 보다 쉽게 인식할 수 있도록 하였다. 또한 list 엘리먼트 click시, 해당 엘리먼트에 대한 정보가 info 섹션에 보여지도록 하였고, 구성으로는 id, name, location, parent(부모), child(자식)(개수)를 표시하였다, 이후 엘리먼트 개별 색상을 변경 할 수 있는 기능 추가(해당 기능에 대해서는 전체적인 eleSlice에 대한 수정 작업이 필요)예정이며, 엘리먼트의 name은 dragSection / info에서 변경 가능하도록 기능추가를 완료하였다.

Learn

  • 점점 Redux에 대해 깊게 이해하며, 원하는 방식으로의 사용이 가능하다.
  • 랜더링 조건 및 방식에 대해 간과했던 부분을 복습하고, 랜더링이라는 기능을 이용해 보다 깔끔하고 효율적인 코드작성에 대해 깊이 알아 가고 있다.
  • 프로젝트 제작에 있어 구성이나 연결점들을 보다 빠르고 쉽게 파악하여 이를 이용한 유지보수(수정)에 있어서 코드 리딩능력이 향상되고 있다.

0531

ColorPicker 추가

  • info 섹션에 Background 요소를 추가하여 선택한 요소의 배경색상을 변경 할 수 있는 기능을 추가하였다. (react color 사용 (typescript))
  • 해당 기능을 추가함으로서 eleSlice / ElementObj에 color요소를 추가하였고, colorEle 리듀서를 통해 변경 가능한 기능 생성.

Zoom 기능

  • 마인드맵에 대한 전체적인 뷰를 볼 수 있도록 Zoom In/Out 기능을 추가
    !! transform.scale을 사용한 zoom기능이지만, 해당 기능을 사용했을시, scale이 1이 아닌 상태에서 element의 drag기능에 오류발생

Learn

  • colorpicker의 사용

0602

UI 조정

  • UI조정

엘리먼트 연결선

  • 엘리먼트간의 연결선에 대한 세부사항 (border - width, color, type) 등에 대한 변결이 가능하도록 한 기능을 추가

0605

ElementEdit 컴포넌트 제작

  • info의 style수정버튼을 통해 로드할수 있으며, 엘리먼트의 width, height, border(width, style, ...), background-color 등의 스타일요소를 수정할 수 있다. 수정시에는 좌측의 미리보기를 통해 어떻게 적용될수 있는지 미리 확인하고 적용 할 수 있다.

Property edit

  • 마인드맵 전체의 배경색 변경기능 추가.

0606

Element 요소 파일 세분화

  • 추가, 삭제, 내용수정의 기능을 따로 분리.

0607

interface 파일을 생성

  • 프로젝트 내의 모든 interface 및 type 에 대한 모든 코드를 저장하여, 프로젝트내부에 중복된 interface를 선언하지 않고 필요에 따라서 extends를 사용하여 코드의 재사용성을 높이고자 한다.

드래그시 발생하는 고스트 이미지 제거

  • 이전에 고스트 이미지를 제거하는 방식으로는 대체할 캔버스를 생성하여 고스트이미지를 대체했지만, 캔버스 엘리먼트가 생성됨으로서 y축 스크롤바가 생성/제거 됨으로, 이를 대체할 방식을 위해 고스트이미지를 제거하는것이 아닌 대체하는 방식을 사용하였다.
  • 이미지 객체를 생성하고, 해당 객체의 src를 따로 지정하지 않음으로 드래그시 발생되는 고스트 이미지가 없는것으로 나타나게 된다.

Element edit 수정

  • width,height 설정에 fit-content값을 추가 할 수 있도록 설정

0609

연결선(Line.tsx) 오류 수정 작업 (1)

  • 고정적인 크기를 가지고 있던 엘리먼트가 element edit을 추가함으로서 크기를 변경할 수 있게 되었고 이로 인해 연결선의 시작/끝 지점을 드래그시에 정하게 되는데, 크기 변화로 인해 시작/끝 점이 엘리먼트 바깥으로 지정 되는 오류가 발생하였다
  • 이를 위해 세부적인 조건을 추가하여 코드 수정을 진행하였지만, 정확안 해결이 되지 않았다.
    =>이후에 추가 수정 작업

0611

연결선(Line.tsx) 오류 수정 작업 (2)

  • 이전 수정 작업을 초기화가고 다른 구성의 새로운 코드를 작성할 필요가 있음.

0613

연결선(Line.tsx) 오류 수정 작업 (3) - tan계산 오류

계산값에 의하여 일정구간에서 tan계산이 ex) 85 => -85 로 바뀌는 의도하지 않은 오류 발생.

  • 탄젠트 값 +
  • 탄젠트 값 -

y축의 변화에 따라 오류가 발생하는데 시작점 - 도착점 - 도착원반지름을 계산하여 연결선의 위치, 각도 길이 등의 요소를 도출해내지만, 시작점 - 도착점 - 도착원반지름 해당 식에서 -값이 나오게 되면 tan가 -값을 도출하여 연결선의 방향이 반대방향으로 그려지게 되는 것이다.


0614

연결선(Line.tsx) 오류 수정 작업 (3)

  • 지속적으로 발생되는 문제는 요소의 크기에 변화를 주었을 때다.
  • 기본적인 연결선 계산이 각 요소의 중앙위치를 기준으로 삼각형을 그리고 tan와 빗변길이를 구하는 것을 통해 각도와 선의 길이를 구하는데, position:absolute에서 기본적인 위치를 좌측상단을 기준으로 하게됨으로, 원의 지름(혹은 사각형의 넓이/높이)을 각 x,y에 더해줌으로서 중앙점의 위치를 도출한다.
  • 다만 원하는 내용의 길이 혹은 정해진 크기에 따라 요소의 크기를 변화시키는 기능을 사용하게 됨으로 크기가 변하는 것은 불가피하고 이에따른 중앙점에 대한 계산을 해야한다.
    => 이부분에서 문제가 발생하며, 초기 크기(100px,100px)일시에는 오류가 발생하지 않는다.
  • 요소(드래그요소)를 직접 변경하는 방식도 고려해볼만하다.
    position 속성을 사용하여
<outer absolute sizeUnchangeable propertyUnchangeable>
	<inner absolute sizeChangeable propertyChangeable>
    	outter의 크기는 고정, inner의 위치는 outter에 속해있으며,
        사용자가 시각적으로 볼 수 있는 것은 inner이다.
        즉, 모든 시각적 요소는 inner에 속해있지만, drag 및 location은 
        outter에 속해있으므로 inner의 크기변화에도 outter에 연결되어 있는
        line(연결선)은 영향을 받지 않는다.
    </inner>
    이를 적용하기 위해서는 inner를 drag하지만 정작 음직이는것은 outter가 되도록 해야하며,
    각 요소에 부여한 id의 값을 변경(추가/상속)하는 방식을 사용하여 기존 기능과 문제없이
    작동하도록 제작해야 한다.
</outer>

연결선(Line.tsx) 오류 수정 작업 - 해결

상위에서 언급한 방식으로 drag요소를 outter-inner-contents 형태로 수정하여 연결선계산에 대한 의도치 않은 오류 해결

  • outter요소 : drag관련 모든 속성 및 이벤트 할당, style속성을 통해 현재위치 location 입력, position:absolute
  • inner요소 : contents를 담기위해 position: relative; 고정적인 넓이/높이(width: 100px; height: 100px;)를 통해 보다 간편한 연결선계산식 사용
  • contents요소 : 기본속성에서 absolute를 통한 가운데 정렬top,left,translate, 기존 drag관련 속성 및 이벤트 제거

문제해결


0615

메뉴 정렬 기능

  • 사용자 편의성을 위해 메뉴위치를 수평/수직 변경 기능 추가
  • 추후 drag 및 추가 기능을 통해 사용자 수정을 할 수 있도록 예정

0617

UI 수정

  • 메뉴 및 기타 UI 수정
  • list에서 엘리먼트 이름에 hover시, 해당 엘리먼트를 파악 할 수 있도록 스타일 추가/제거 기능

마인드맵 크기 설정 기능 계획

  • 이전에 휠 기능을 통해 페이지 확대/축소 기능을 추가했지만, 마인드맵 크기를 절대적 수치로 설정 하지 않았기 때문에 사용함에 있어 잦은 오류가 발생했었다.
  • 그러므로 이번에 마인드맵 크기를 절대적 수치로 설정할 수 있도록 하고, 이를 통해 확대/축소 및 드래그를 통해 전체적인 페이지 좌표이동이 가능하도록 기능을 추가 할 예정이다.
  • 이에따라, 요소 이동에 계산되는 좌표 설정을 수정해야 할 필요가 있다.

0619

list 기능 메소드 수정

  • 0617 의 UI수정 부분에서 엘리먼트의 id를 통해 DOM을 조작하여 각 스타일 속성을 직접적으로 추가(doc.style.backgroundColor = ...) 하도록 했는데, 해당 부분에 대해 이전에 엘리먼트에 오버시 적용되는 속성과의 중첩으로 인해 일부분 적용되지 않는 오류에 대한 수정.
    스타일 속성을 직접 추가 하는 것이 아닌, classList.add()를 통해 클래스 추가 및 제거

HTML to Image

  • 마인드맵을 이미지로 다운도드 할 수 있도록 하기위해 html-to-imagedownloadjs 라이브러리를 설치.
  • html-to-image를 이용하여 지정한 html (id 사용)을 여러 이미지형식(jpeg, png, ...)의 파일로 쉽게 변환이 가능하다.
  • downloadjs 라이브러리는 html-to-image에서 이미지를 다운로드 받기 위한 기능을 사용하기 위해 필요한 라이브러리이다.

! html-to-image >> npm install --save html-to-image
! downloadjs >> npm i --save-dev @types/downloadjs

마인드맵 크기 설정(1)

  • property -> edit 에 페이지 크기 설정 기능 추가.
  • pageSlice (redux)의 value에 width,height를 추가하고, dragSection의 최상위 엘리먼트의 style 속성으로 width,height를 설정하고 해당 값이 redux에 의해 변동되도록 설정하였다.

0620

마인드맵 이동 (마인드맵 크기 설정(2))

  • drag 혹은 onmousedown이벤트를 사용하여 네이버, 구글 등과 같은 맵 어플리케이션에서 지도를 이동하는 방식과 같은 기능을 추가하여 맵을 자유자재로 이동시키므로 보다 편리한 마인드맵 구성이 가능하도록 하는 목표.
  • 기본적인 기능은 해당 링크를 참고.
  • 위 링크를 참고하여 제작, 다만 마인드맵의 범위를 벗어나가므로 불필요한 이동이 진행되는 것을 확인. 추구하는 기능적 목표는 드래그와 같은 기능을 통해 이동하는 것이나, 마인드맵크기 이상의 이동은 불가능 하도록 제한하는것.

기능 수정

  • 마인드맵이 좌표(0,0)이내로 들어올시 다시 (0,0)으로 초기화 복귀. (해당 기능은 불필요한 이동범위를 최소한으로 하기 위함으로 이후 작업에 따라 변경 될 수도 있음)

오류!

  • 마인드맵 container가 dragElement상위에 위치하다보니 element 드래그시에 마인드맵 container의 onmousedown, onmousemove이벤트도 같이 활성화가 되는 현상 발생.

0622

마인드맵 이동 (2)

  • 해결책을 찾지 못함...
  • 문제점
  1. 마인드맵 요소를 이동시키기 위해(드래그) 클릭을 하게되면 전체 마인드맵 이벤트가 선 실행 후 요소 드래그이벤트 실행.
  2. 요소 드래그가 가능하지만, 드래그가 끝난 이후 처음 이동을 시작했던 지점에서 전체 마인드맵 이벤트가 연달아서 실행되는 의도치 않은 오류 발생.
  3. 결과적은 요소 드래그시 덩달아 발생되는 전체 이벤트의 제어가 필요함. 다만 전체 맵 이벤트는 최상단 부모요소로 부터 발생하기 때문에 선 실행 되는 것임으로 기본 제어하기가 까다로움.
  4. 현재 요소를 드래그시 dragOn의 false/true 로 드래그시 다른 이벤트가 동시 발생되는것을 방지하고자 했지만, 드래그 이후에 발생되는 이벤트의 제어가 필요.

요소 드래그 이후 드래그시작지점에 마우스가 고정되어 전체 맵에 대한 이동이 연쇄적으로 이루어지는 오류.(마우스위치는 gif 녹화 오류)


0623

마인드맵 이동 (3)

해결완료

  let _startX = 0;
  let _startY = 0;
  let _offsetX = 0;
  let _offsetY = 0;
  let _dragElement: HTMLDivElement | null;

  function OnMouseDown(event: any) {
    _startX = event.clientX;
    _startY = event.clientY;
    _dragElement = document.getElementById('dragSection') as HTMLDivElement;
    _offsetX = _dragElement.offsetLeft;
    _offsetY = _dragElement.offsetTop;
    console.log('page start');
  }

  function onMouseMoveHandler(event: any) {
    if (_dragElement !== null) {
      _dragElement.style.left = _offsetX + event.clientX - _startX + 'px';
      _dragElement.style.top = _offsetY + event.clientY - _startY + 'px';
      console.log('page drag');
    }
  }

...

<div onMouseMove={move ? undefined : onMouseMoveHandler} >
  //마인드맵 요소 1,2,3 ...
  </div>
  • 이전에는 마인드맵 요소를 드래그 하면, redux의 move(boolean)를 true로 바꿈으로서 onMouseMoveHandler에 조건문 if(!move){}를 사용함으로 페이지 드래그를 제어하려고 했었다.
  • 하지만 마인드맵 이동 (2)에서의 문제와 같이 맵과 요소 두 개의 이벤트가 동시에 활성화되어 의도치 않은 오류를 발생하였다. 따라서, onMouseMoveHandler만을 정확히 제어하는 코드작성이 필요하게 되었다.
  • 이전에는 OnMouseDowndocument.onmousemove = onMouseMoveHandler를 할당하여 마우스 다운시 onMouseMoveHandler가 실행되도록 했었지만 위에서 언급한 오류를 야기하였다. 최종 해결방안으로는 onMouseMoveHandler이벤트 할당을 document가 아닌 모든 요소를 자식으로 가지는 div에 직접적으로 할당을 하였고, move에 의해 이벤트의 할당여부를 결정하는 방식으로 코드를 수정하였다.
  • 결과적으로 이전에 발생하였던 의도치 않은 오류가 해결되었고, 오히려 각 기능에 대한 기능을 보다 직관적으로 이해할 수 있는 가독성이 향상된것을 느끼게 되었다.

0624

마인드맵 이동 후 오쇼 그래그 오류 문제

  • 문제 : 전체마인드맵을 그래그하여 이동 한 이후 요소에 대해 그래그 이동을 할 시 오류 발생
  • 분석 : 개발당시에 inner크기에 대해 위치를 설정한 것으로 인해 발생한 오류라고 생각된다.
    드래그 이동시 마인드맵 크기, 윈도우창 크기, 현재 view에 들어와있는 부분(좌표) 3가지를 계산하여 실질적인 위치좌표를 설정해야 할 것으로 예상된다.

작업

  • 이동한 마인드맵의 좌표를 토대로 현재 view에 보여지는 영역을 계산하여, 좌표를 설정.
    -> 전체 마인드맵 - view밖의 영역 + client좌표 (예정)
  • 마인드맵의 x,y좌표를 여러 컴포넌트에서 사용하기위해 onMouseMoveHandler에 location변수 설정 및 pageSlice 리덕스에 저장. 마우스 움직임마다 반복적으로 실행되는 dispatch를 방지하기위해 lodashdebounce를 사용하여 이동한 마지막 좌표를 리덕스에 저장.
    -> pageLocation
  • 이전에는 event.clientX(Y)를 사용해 좌표를 구하고 위치를 설정했다면, 이제는 마인드맵 크기에 반응해야 하기 때문에 마인드맵 크기pageLocation를 이용해야 한다.
  • 위 사진 처럼 위치를 계산하였다. pageLocation(X | Y) + Client(X | Y)를 하면 마인드맵 전체 크기에 대한 좌표를 설정할 수 있다. 다만 그림처럼 상대적으로 client보다 높은 위치를 가지게 되면 좌표가 (-)가 될 수 있기에 Math.abs()를 사용하여 값에 대한 절대값을 사용하였다.
  • 다만, 요소 이동시 pageLocation이 달라지고 이에 대한 연산을 해야하는 이유에서인지, 이동 시작시 잠깐 포인터가 밖으로 튀는 현상이 발생한다.

마인드맵 이동 (4) - 추가 오류

  • 개발도중 콘솔창에 엄청난 오류메세지가 출력되는것을 확인, onMouseMoveHandler에서 style속성을 읽지 못한다는 오류메세지.
  • 위에서 언급하지 않은 onMouseUp이벤트가 존재하는데 이는 mouseUp시에 _dragElement의 값을 null로 바꿔주는 것이다. 이것과 더불어 onMouseMove={move ? undefined : onMouseMoveHandler}부분에서 move의 값이 false일시에는 onMouseMoveHandler가 항시 발동중이게 된다.
    즉, 드래그를 하지 않을 때에도 _dragElement 값은 null이고, onMouseMoveHandler는 항시 작동중이니 style속성을 읽지 못한다는 오류메세지가 출력되는 것이다.
  • 다만, _dragElement가 null일때에는 onMouseMoveHandler가 의도적으로 정상실행되지 않아야 하는 타이밍이기에, 작동에는 문제가 되지 않고 오류 메세지만 출력되고 있었다.

해결

  • if (_dragElement !== null) 에서 if (_dragElement)로 변경
  • _dragElement는 기본적으로 null이 아닌 undefined 였다... 그러므로 null이 들어가는 부분에 대해 undefined를 할당하도록 했다. (수정 이후 확인)

Zoom 기능

  • 이전에 간단히 작업해봤던 Zoom은 기능 사용시 확대/축소가 된 상태에서의 drag시, 오류가 발생했었다. 이전 기능은 transform : scale()을 사용했었다.

0625

Zoom (2)

  • 목표 : (1)에서 기재했던 오류를 해결한 Zoom기능 구현
  • 분석 : 마인드맵이동 처럼 맵의 크기, client좌표, 확대/축소 비율의 차이를 계산하여 좌표를 설정하는 방법.
  • 이전에 transform의 scale을 사용했다면, 이번에는 직접 크기에 비율을 계산하는 방식을 사용한다.
  • 요소의 넓이, 높이 등의 수치를 '000px'인 string으로 저장했기에 비율계산을 위해 number로 저장, 이와 관련된 모든 코드를 수정한다.
  • 마인드맵 상위 div에서 휠 이벤트 발생 시, pageSlice에 추가된 scale 속성을 변화시키며, 해당 속성을 통해 마인드맵의 크기, 요소의 크기에 곱 적용 width*scale을 통해 정상적으로 공통된 크기를 표시 할 수 있도록 하였다. 또한 드래그를 통한 위치 이동에는 좌표 + e.clientY / scale - 50 / scale의 계산식으로 확대/축소시 드래그가 정상적으로 작동하도록 설정하였다.
  • 연결선 또한 같은 방법을 통해 위치계산을 적용하였다.
  • 확대/축소 시, 편의성을 위해 배율이 정중앙에 잠시 1초 동안 표시되는 기능 추가.
  • 간혹 일정 조건에서 오류가 순간적으로 발생하는 현상 확인.

Alarm && Delete

  • 자식을 가지는 요소를 삭제할 시, 자식을 포함한 요소를 전체삭제 할 것인지 yes 아니면 취소 할 것인지 No를 묻는 팝업 알림창 기능 추가.
  • redux를 통해 알림창 팝업 여부를 업데이트하고, 알림창에 사용될 텍스트 및 데이터를 alarmSlice의 속성데이터로 전달하여 Alarm컴포넌트에서 Yes를 선택할 시, eleSlice(요소redux)의 delAllEle(선택적전체체요소삭제)리듀서에 alarmSlice의 속성데이터로 저장된 요소의 id를 전달해 해당 id와 관련된 요소(부모제외)를 전체 삭제하도록 하였다.

0627

마인드맵 이동 (5)

연쇄적으로 문제발생.

  • 요소 드래그시 맵 전체가 살짝 이동되는 현상이 발생하는데, 이로인하여 zoom의 1배율이 아닌 모든 배율상태에서 요소 드래그에 오류가 발생.

해결 대책 방안안

  • (1) : 맵을 이동시키는 것이 아닌 브라우저 크기의 임이의 view창을 만들어 해당 창의 이동으로 설정
  • (2) : 최하단 자식 엘리먼트로 맵의 백그라운드를 담당하는 영역을 생성함으로 보다 상위에 위치하게 되는 마인드맵 요소 드래그시 이전에 발생했던 문제인 부모의 이벤트가 발생되는 것을 방지.

0629

일부 수정

  • Zoom기능 수정

0630

Drag 관련 함수 리팩토링 및 분리 작업


0701


0702

  • 0627의 최하단 엘리먼트 대체작업을 시도하였지만, 결과적 실패.

0703

마인드맵 이동 (5) - 페이지 이동 이슈(1)

  • 여전히 1000ms가 안되는 잠깐동안의 의도치 않은 동작으로 인해 오류가 지속적으로 발생.

  • 위 사진은 함수가 실행되는 순서를 보여주는 콘솔창 로그이다.
    -
    • page start : 페이지, 마인드맵 관련 이동 시작시 실행 함수
    • page drag : 페이지, 마인드맵 이동 시 (drag) 실행 함수
    • drag click : 마인드맵 요소 클릭시 실행 함수
    • drag drag : 마인드맵 요소 이동 시 (drag) 실행 함수
    • drag end : 마인드맵 요소 이동 종료 시 실행 함수
  • 문제 : page drag 는 실행되어야 하지 말아야 한다. 이것이 실행됨으로서 마인드맵의 좌표가 달라지게 되고, 이로인해 좌표계산에 오류가 발생함으로 최소 기능발현의 지연 혹은 에러발생까지 유발한다.
  • drag click, drag drag 시에 이동관련 boolean을 설정하여 true일시 page관련 함수가 실행되지 않도록 하였지만, 짧은 실행시간 사이에 해당 기능 관련 오류가 발생. - X
  • 요소에 onmouseover/leave를 적용하여 boolean 값을 변경하는 것을 사용해봤지만, 정말 말도 안되게 좌표계산에 오류가 발생.(왜?????) - X

0704

페이지 이동 이슈(2)

예상 오류 발견 ( 오류 이것인거 같은데?)

  • 변경 전의 페이지 이동 기능의 발생 순서는
    -
    • onMouseDown을 통해 현재 페이지의 위치를 확인 및 저장 client , offset
    • onMouseMoveHandler를 통해 이동되는 페이지의 위치를 저장 locationdebounce를 사용해 redux에 저장
    • onMouseUp을 통해 페이지의 최종적인 위치를 변경. 현재 구현하고자 하는 것이 사용자 브라우저의 뷰를 벗어나게 하지 않기 위해서 위치를 강제적으로 변경.
  • onMouseUp에서 문제점을 확인하게 되었는데, 페이지 및 요소 관련된 모든 기능에서 계산적인 부분의 오류를 발견해내기 위해 console.log를 통해 모든 좌표계산을 확인하던 중 확인.
  • 위와 같이 마인드맵의 위치가 (0,0)보다 크게되면 초기 위치로 변경되도록 하였는데, 이때 초기 위치가 아닌 마지막 이동이 이루어진 좌표가 저장되어 이후의 모든 이동 관련 계산에 영향을 주는 것을 확인 하였다.
  • 따라서, onMouseMoveHandler에서 redux에 저장되도록 하는 코드를 debounce를 제거하고 onMouseUp에 할당하여 onMouseUp이 실행되어야만 실질적인 이동이 이루어 지도록 하였다.
  • 또한, 초기위치(0,0)로 바꾸는 코드와 함께 location의 위치도 함께 변경되도록 수정하였다.
  function onMouseUp(event: React.MouseEvent<HTMLDivElement>) {
    if (_dragElement) {
      const y = _offsetY + event.clientY - _startY * pageStyle.value.scale;
      const x = _offsetX + event.clientX - _startX * pageStyle.value.scale;
      document.onmousemove = null;
      if (y > 0) {
        _dragElement.style.top = 0 + 'px';
        loaction['y'] = 0;//추가. location은 컴포넌트 전역변수
      }
      if (x > 0) {
        _dragElement.style.left = 0 + 'px';
        loaction['x'] = 0;//추가
      }
      //상단 범위 내부로 전체 엘리먼트가 들어올시 (0,0)으로 강제 이동.
      if (window.innerHeight > pageStyle.value.height + y) {
        _dragElement.style.top =
          (window.innerHeight - pageStyle.value.height) *
            pageStyle.value.scale +
          'px';
        //하단 동일
      }
      if (window.innerWidth > pageStyle.value.width + x) {
        _dragElement.style.left =
          (window.innerWidth - pageStyle.value.width) * pageStyle.value.scale +
          'px';
        //하단 동일
      }
    }
    _dragElement = undefined;
    console.log('page end');
    dispatch(setPageLocation(loaction));//redux저장(debounce를 제외)
  }
  • 따라서, 요소 컴포넌트에 onMouseOver onMouseLeave를 사용해 redux-drag 옵션을 true-false 변경하도록 설정함으로서 요소 이동이 의도치 않은 마인드맵 이동이 실행되지 않도록 수정.

페이지 이동 이슈 (3)

마인드맵이 뷰포트 밖으로 이동시 의도적으로 위치를 재조정 한다.

  • 마인드맵의 크기가 뷰포트 밖으로 완전히 벗어남으로 인해 위치를 재조정 할 수 없는 상황에 대비해 해당 기능을 추가하였다.
  • 뷰포트 크기 > 마인드맵 크기 일시 마인드맵이 정중앙에 위치할 수 있는 기능도 추가할 예정.

수정 코드

  function onMouseUp(event: React.MouseEvent<HTMLDivElement>) {
    const fixedY =
      (window.innerHeight - pageStyle.value.height) * pageStyle.value.scale; // note1 : zy
    const fixedX =
      (window.innerWidth - pageStyle.value.width) * pageStyle.value.scale; // note1 : zx
    
    if (_dragElement && !move) {
      const y = _offsetY + event.clientY - _startY * pageStyle.value.scale;
      const x = _offsetX + event.clientX - _startX * pageStyle.value.scale;
      document.onmousemove = null;
      if (y > 0) {
        _dragElement.style.top = 0 + 'px';
        location['y'] = 0;
      }
      if (x > 0) {
        _dragElement.style.left = 0 + 'px';
        location['x'] = 0;
      }
      //상단 범위 내부로 전체 엘리먼트가 들어올시 (0,0)으로 강제 이동.
      if (window.innerHeight < pageStyle.value.height * pageStyle.value.scale) {
        // 뷰포트가 마인드맵보다 작을 때
        if (fixedY > location.y) {
          //y(높이)가 최대치를 벗어났을 때
          _dragElement.style.top = fixedY + 'px';
          location['y'] = fixedY;
        }
      } else {
        // 뷰포트가 마인드맵보다 클 때
        _dragElement.style.top = 0 + 'px';
        location['y'] = 0;
      }

      if (window.innerWidth < pageStyle.value.width * pageStyle.value.scale) {
        // 뷰포트가 마인드맵보다 작을 때
        if (fixedX > location.x) {
          //x(넓이)가 최대치를 벗어났을 때
          _dragElement.style.left = fixedX + 'px';
          location['x'] = fixedX;
        }
      } else {
        // 뷰포트가 마인드맵보다 클 때
        _dragElement.style.left = 0 + 'px';
        location['x'] = 0;
      }
    }
    _dragElement = undefined;
    if (location !== undefined) {
      //해당 부분은 요소 이동시 undefined인 location변수가 redux에 업데이트 되어, 
      //오류를 발생시키므로 location !== undefined일 때만 실행
      dispatch(setPageLocation(location));
    }
  }

해당 컴포넌트에서 중복되는 값들의 정리 필요.

요소 삭제 오류 (1)

  • Layer가 깊게 형성된 요소를 삭제할시 코드상에는 삭제하는 자신 + 1단계 차이의 자식만 삭제되는것만 구현하였으므로, 요소1-자신-요소2-요소3와 같이 깊게 중첩되면 요소3에 대해 연결선의 위치계산이 성립되지 않음으로 오류를 발생시켰다.
    - 오류 개선 방식 (택1)
    • 1 : 삭제 요소의 모든 자식요소 삭제 (삭제 편리성)
    • 2 : Layer 중첩이 2개 이상이면, 삭제 불가 (실수 방지)
    • 3 : ?

0705

마인드맵 저장 및 불러오기

제작한 마인드맵을 저장/불러오기를 통해 어디서나 사용할 수 있도록 하는 기능을 추가한다.

  • 백엔드를 사용하지 않은 정적인 페이지 제작이기 때문에 저장 기능에 대해서는 두가지 옵션이 있다.
    - 옵션
    • 사용자 PC에 데이터가 들어있는 파일(txt)저장(다운로드)
    • LocalStorage를 통해 브라우저에 데이터 저장
  • 사용자 PC에 데이터가 들어있는 파일(txt)저장(다운로드)를 사용하기로 하였다.
  • 선택 이유로는 해당 데이터파일을 통해 다른 PC를 통해 사용가능하며, 타 이유로 인해 삭제되는 상황이 발생하지 않으며, 다수의 마인드맵 제작시 이전 데이터를 보전할 수 있다. 결과적으로 LocalStorage를 사용함으로서 나타나는 여러 단점을 txt다운로드를 통해 보완할 수 있다.

저장 / 다운로드

  • 파일(txt)에 저장하기 위해서, 마인드맵 데이터와 요소 데이터를 결합하여 BlobcreateObjectURL을 이용하여 다운로드 가능한 형식으로 변환.
  • 각각의 데이터를 page, element로 나누어 이후에 불러오기에서 보다 편리하게 데이터를 다룰수 있도록 하였다.
  const saveHandler = (
    element: ElementObj[],
    page: PageType,
    filename: string
  ) => {
    const file = JSON.stringify({ page: page, element: element });
    const blob = new Blob([file], { type: 'text/plain' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    setTimeout(() => {
      document.body.removeChild(a);
      window.URL.revokeObjectURL(url);
    }, 100);
  };

불러오기

  • input태그 속성의 file을 사용, 불러온 파일을 fileReaderonloadreadAsText를 사용해 데이터를 redux에 저장 및 읽기를 실행할 수 있도록 하였다.
    const fileOnChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
       const selectedFile = e.target.files; //.files[0];
       let fileText;
       if (selectedFile !== null) {
         const reader = new FileReader();
         reader.onload = () => {
           if (typeof reader.result === 'string') {
             fileText = JSON.parse(reader.result);
             dispatch(setElement(fileText.element));
             dispatch(setPageSetting(fileText.page));
             console.log(fileText);
           } else {
             console.log('not string');
           }
         };
         reader.readAsText(selectedFile[0]);
       }
     };

오류

  • 저장 및 불러오기는 정상적으로 작동하나, redux의 상태를 업데이트하는 과정에서 새로 추가하는 데이터는 정상적으로 업데이트 되지만, initialState에서 정의한 데이터는 업데이트가 되지 않고 초기상태를 그대로 가지고있는 것이 확인되었다.

0707 ~ 0720

첫 페이지 및 마인드맵 UI 및 디자인 구성

  • 소개 및 사용 설명 페이지
  • 마인드맵 페이지

0720 ~

외부요소 마무리 (~0720)

전체적인 리팩토링과 중복코드 수정작업 (0720~)


0728 ~

전체적인 마무리 작업. 남은 작업

  • 프론트페이지의 center 내부의 소개내용 수정
  • 이외의 scss정리 및 컴포넌트 분리 조정
  • 기능관련 작동 함수 검토
profile
복잡한 문제를 쉬운 코드로 해결해 나가는 개발자

0개의 댓글