DOM 또는 "Document Object Model"을 조작하는 것은 웹 개발의 핵심입니다. [MDN](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction)에 따르면, "The Document Object Model (DOM) is the data representation of the objects that comprise the structure and content of a document on the web." 이라고 합니다. 웹의 DOM 조작과 관련하여 간혹 DOM을 관리하기 위해 순수 JavaScript 대신 JavaScript 프레임워크를 도전하게 되는 원동력이지만, 우리는 스스로 관리할 것입니다!
> DOM을 웹 페이지 문서를 제어할 수 있는 모든 방법으로 나타낼 수 있는 트리로 생각하십시오. 프로그래머가 선택한 프로그래밍 언어를 사용하여 DOM에 접근하고 편집, 변경, 재배치하며 관리할 수 있는 다양한 API(Application Program Interfaces)가 작성되어 있습니다.
> DOM과 참조하는 HTML 마크업의 표현입니다. From [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
> Note: 외부 JavaScript 파일을 html 파일로 가져올 때 `defer` 를 사용하여 HTML 파일이 완전히 불러질 때만 JavaScript가 실행되도록 합니다. HTML 파일이 파싱되는 동안 스크립트를 실행할 수 있는 `async` 속성을 사용할 수 있지만, 우리는 드래그 스크립트를 실행하기 전에 HTML 요소를 완전히 드래그할 수 있어야 한다는 점이 중요합니다.
여기서 어떤 일이 일어나고 있나요? 특정 Id의 요소를 찾기 위해 문서를 참조하려고 해당 DOM을 봅니다. HTML에 대한 첫번째 강의에서 각 식물 이미지(`id="plant1"`)에 개별 Id를 준 것을 기억하시나요? 이제 그 노력을 쓰겠습니다. 각 요소를 식별한 후, 1분 안에 작성될 `dragElement`라고 불리는 함수에 해당 아이템을 전달합니다. 따라서 HTML의 요소는 이제 드래그를 할 수 있거나 곧 합니다.
`dragElement`는 스크립트 상단의 선언에서 `terrariumElement` 객체를 가져옵니다. 그러고, 함수에 전달된 객체의 일부 로컬 위치를 `0`으로 설정합니다. 클로저 안에서 드래그 앤 드롭 기능을 각 요소에 추가할 때 각 요소에 대해 조작될 지역 변수입니다. terrarium에 드래그된 요소로 채워지므로, 애플리케이션은 배치된 위치를 추적해야 합니다.
추가로, 이 함수에 전달되는 terrariumElement에는 DOM 관리에 도움이 되도록 설계된 [web APIs](https://developer.mozilla.org/docs/Web/API)의 일부인 `pointerdown` 이벤트가 할당됩니다. `onpointerdown`은 버튼이 눌리거나 드래그 하는 요소가 터치될 때 발생합니다. 이 이벤트 핸들러는 몇 가지 예외를 제외하고, [웹과 모바일 브라우저](https://caniuse.com/?search=onpointerdown) 다 작동합니다.
✅ [event handler `onclick`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onclick)은 크로스 브라우저 지원이 훨씬 더 많습니다. 왜 여기서 사용하지 않나요? 여기에서 만들고자 하는 정확한 화면 상호작용 타입에 대해 생각해보세요.
terrariumElement를 드래그할 준비가 되었습니다; `onpointerdown` 이벤트가 시작되면, pointerDrag 함수가 호출됩니다. 줄 바로 아래에 해당 함수를 추가하시기 바랍니다: `terrariumElement.onpointerdown = pointerDrag;`:
다음으로 지역 변수 'pos3'과 'pos4'가 어떻게 e.clientX 로 설정되어 있는 지 확인합니다. 검사 창에서 `e` 값을 찾을 수 있습니다. 이 값은 식물을 클릭하거나 터치하는 순간 식물의 x 와 y 좌표를 캡처합니다. 식물을 클릭하고 드래그할 때 식물의 동작을 세밀하게 제어하여 좌표를 추적해야 합니다.
제 식물을 이동할 때 포인터와 함께 식물을 끌고, 식물 선택을 취소할 때 드래그 제스처를 중지하도록 지정합니다. `onpointermove` 와 `onpointerup`은 모두 `onpointerdown`과 동일한 API의 일부입니다. 아직 `elementDrag` 및 `stopElementDrag` 함수를 정의하지 않아 인터페이스에서 오류가 발생하므로, 다음에 작성하십시오.
식물을 드래그하고 멈출 때 일어나는 일을 처리하는 두 내부 함수를 더 추가하여 클로저를 완료합니다. 원하는 동작은 언제든지 식물을 드래그하여 화면의 아무 곳에 둘 수 있다는 것입니다. 이 인터페이스는 식물을 추가, 제거 그리고 재배치하여 원하는대로 terrarium을 정확하게 디자인할 수 있도록 (예를 들어 drop zone이 없음)하는 것에 의견이 없습니다.
드래그할 때, `pos1`을 현재 `e.clientX` 값을 뺀 `pos3`(이전에`e.clientX`로 설정)과 동일하게 만들어 `pos1`을 다시 할당합니다. `pos2`와 유사한 작업을 수행합니다. 그런 뒤에, `pos3`과 `pos4`를 요소의 새로운 X 와 Y 좌표로 다시 설정합니다. 드래그하면 콘솔에서 변경 사항을 볼 수 있습니다. 그런 뒤에, 식물의 css 스타일을 조작하여 `pos1`과 `pos2`의 새로운 위치를 기반으로 위치를 설정하고, 오프셋을 이러한 새 위치와 비교하여 식물의 위쪽과 왼쪽 XY 좌표를 계산합니다.
화면에서 요소를 드래그하는 것은 사소한 것처럼 보이지만, 원하는 효과에 따라 여러 가지 방식과 함정이 있습니다. 실제로, 시도할 수 있는 전체 [drag and drop API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API)가 있습니다. 우리가 원하는 효과가 다소 다르기 때문에 이 모듈에서는 사용하지 않았지만, 그러나 이 API를 자신의 프로젝트에서 시도해보고 얻을 수 있는 게 무엇인지 확인하시기 바랍니다.
포인터 이벤트에 대한 자세한 내용은 [W3C docs](https://www.w3.org/TR/pointerevents1/)와 [MDN web docs](https://developer.mozilla.org/docs/Web/API/Pointer_events)에서 확인하세요.