<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>1K3H</title>
        <link>https://velog.io/</link>
        <description>즐거웁게 코딩합시다.</description>
        <lastBuildDate>Sat, 13 Mar 2021 13:43:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. 1K3H. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/home_2201" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[시계를 만들자 (HTML, CSS, JS)]]></title>
            <link>https://velog.io/@home_2201/%EC%8B%9C%EA%B3%84%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%9E%90-HTML-CSS-JS</link>
            <guid>https://velog.io/@home_2201/%EC%8B%9C%EA%B3%84%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%9E%90-HTML-CSS-JS</guid>
            <pubDate>Sat, 13 Mar 2021 13:43:07 GMT</pubDate>
            <description><![CDATA[<p><a href="https://1k3h.github.io/clock/">결과물 확인 링크</a></p>
<p><a href="https://github.com/1K3H/clock">전체 코드 링크</a></p>
<h1 id="💡-발단">💡 발단</h1>
<p>Udemy 강의를 듣던 중 relaxer app이라는 프로그램이 작동하는 원리를 보고 이 원리를 이용하면 시계를 만들 수 있지 않을까 생각했다.</p>
<p><a href="https://vanillawebprojects.com/projects//relaxer-app/">relaxer app 링크</a></p>
<br>

<h1 id="🐱🏍-프로젝트-시작">🐱‍🏍 프로젝트 시작</h1>
<br>

<h2 id="✔-원-만들기">✔ 원 만들기</h2>
<p>index.html</p>
<pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
  &lt;div id=&quot;circle1&quot; class=&quot;circle1&quot;&gt;&lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>style.css</p>
<pre><code class="language-css">* {
  box-sizing: border-box;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  margin: 0;
}

.container {
  position: relative;
  width: 600px;
  height: 600px;
}

.circle1 {
  width: 100%;
  height: 100%;
  border: 1px solid black;
  border-radius: 50%;
}</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/962b3c93-0466-4cfe-a9bf-2d32104784c8/image.png" alt=""></p>
<br>

<h2 id="✔-눈금-만들기">✔ 눈금 만들기</h2>
<p>원을 그렸으니 눈금을 그려야 했는데 원하는 위치에 눈금을 그릴 방법이 막막했다.
아이디어를 얻었던 강의에서는 conic gradient를 사용해서 구역을 나누는 방법을 사용했는데 conic gradient는 색으로 경계를 구분하는 방법이기 때문에 내가 원하는 선으로 구역을 나누는 방법에 적합하지 않았다.</p>
<p>여러가지 방법을 검색해 보다가 원하는 결과를 얻지 못해서 잘 알지 못하는 svg나 canvas를 이용해서 그려봐야 되나 싶던 와중에 내가 필요로 하던 정보를 얻었다.</p>
<p><a href="https://velog.io/@madpotato1713/HTMLCSS-%EB%8C%80%EA%B0%81%EC%84%A0-%EA%B7%B8%EB%A6%AC%EA%B8%B0">[HTML/CSS] 대각선 그리기</a></p>
<p>단순히 div를 만들고 rotate를 이용해서 원하는 각도로 돌리면 된다.</p>
<p>style.css</p>
<pre><code class="language-css">.circle1 .line {
  position: absolute;
  width: 598px;
  background-color: black;
}

.circle1 .line.thick {
  top: calc(50% - 2px);
  height: 4px;
  z-index: 1;
}

.circle1 .line.thin {
  top: calc(50% - 0.5px);
  height: 1px;
}</code></pre>
<p>script.js</p>
<pre><code class="language-javascript">const circle_1 = document.getElementById(&#39;circle1&#39;);

// 눈금 그리기
for (let i = 0; i &lt; 30; i++) {
  const line = document.createElement(&#39;div&#39;);
  line.classList.add(&#39;line&#39;);
  line.style.transform = `rotate(${6 * i}deg)`;
  if (i % 5) {
    line.classList.add(&#39;thin&#39;);
  } else {
    line.classList.add(&#39;thick&#39;);
  }
  circle_1.appendChild(line);
}</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/60f58bfd-f269-467e-94f3-4daa3f3a1c48/image.png" alt=""></p>
<p>맨 뒤에 위치할 circle1을 만들고 나면 그 위를 덮을 원을 두 개 더 만들어서 크기와 z-index를 이용해서 눈금의 길이를 조절한다.</p>
<p>index.html</p>
<pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
  &lt;div id=&quot;circle1&quot; class=&quot;circle1&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;circle2&quot;&gt;&lt;/div&gt;
  &lt;div id=&quot;circle3&quot; class=&quot;circle3&quot;&gt;&lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>style.css</p>
<pre><code class="language-css">.circle2 {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 95%;
  height: 95%;
  background-color: #ffffff;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.circle3 {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 90%;
  height: 90%;
  background-color: #ffffff;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
}</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/cad31b6c-16f0-403d-8dae-2b76a208f3f0/image.png" alt=""></p>
<br>

<h2 id="✔-숫자-넣기">✔ 숫자 넣기</h2>
<p>style.css</p>
<pre><code class="language-css">.num-container {
  position: absolute;
  top: calc(50% - 30px);
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 60px;
  padding: 0 20px;
  transform-origin: center 30px;
}

.num {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 60px;
  height: 60px;
  font-size: 30px;
}

.num.highlight {
  width: 80px;
  height: 80px;
  border: 2px solid black;
  border-radius: 50%;
  font-size: 30px;
  font-weight: bold;
}</code></pre>
<p>script.js</p>
<pre><code class="language-javascript">let right = 3;
let left = 9;

for(let i = 0; i &lt; 6; i++) {
  const num_container = document.createElement(&#39;div&#39;);
  num_container.classList.add(&#39;num-container&#39;);
  num_container.style.transform = `rotate(${30 * i}deg)`;
  num_container.innerHTML = `
    &lt;div class=&quot;num ${i === 0 || i === 3 ? &#39;highlight&#39; : &#39;&#39;}&quot; 
      style=&quot;transform: rotate(-${30 * i}deg)&quot;&gt;${left &gt; 12 ? left - 12 : left}&lt;/div&gt;
    &lt;div class=&quot;num ${i === 0 || i === 3 ? &#39;highlight&#39; : &#39;&#39;}&quot; 
      style=&quot;transform: rotate(-${30 * i}deg)&quot;&gt;${right}&lt;/div&gt;
  `;
  circle_3.appendChild(num_container);
  right++;
  left++;
}</code></pre>
<p>숫자를 위치 시키는 방법을 한참 고민하다가 눈금을 만들었던 과정과 같은 방법으로 해결했다.
양쪽에 숫자를 가지는 num-container를 만들고 30도씩 회전시킨다.
num-container가 회전하면 숫자도 회전하므로 숫자는 -30도 회전하도록 한다.</p>
<p><img src="https://images.velog.io/images/home_2201/post/fc8f40b9-a921-49e1-abeb-93df4cf59b6b/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/home_2201/post/af944721-cd57-453a-a9f3-5d22fc4a45c1/image.png" alt=""></p>
<br>

<h2 id="✔-바늘-만들기">✔ 바늘 만들기</h2>
<h3 id="transform-origin">transform-origin</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin">MDN - transform-origin</a></p>
<p>애니메이션을 적용하는 대상에 transform-origin 속성으로 애니메이션을 실행할 기준점을 정할 수 있다.
시침, 분침, 초침이 회전하는 기준점이 내가 원하는 곳이 아니어서 어떻게 해결하면 될지 검색하다가 transform-origin 속성을 알게 되었는데 대상 요소 내부에서 기준점으로 정할 x좌표, y좌표를 정한다고 생각하면 될 것 같다.</p>
<p>x좌표, y좌표에 더해서 z좌표도 있는데 나중에 활용하면 유용하게 쓸 수 있을 것 같다.</p>
<h3 id="css로-삼각형-만들기">CSS로 삼각형 만들기</h3>
<p><a href="https://css-tricks.com/the-shapes-of-css/">The Shapes of CSS | CSS-Tricks</a></p>
<p>시침, 분침의 끝 부분을 뾰족하게 만들고 싶었는데 네모난 div를 자체적으로 뾰족하게 깎는 방법은 찾지 못하고 ::before 선택자에 같은 너비의 삼각형을 만들어서 시침과 분침에 연결했다. </p>
<p>index.html</p>
<pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
  ...
  &lt;div id=&quot;hour-hand&quot; class=&quot;hour-hand&quot;&gt;
    &lt;div class=&quot;white-space&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div id=&quot;minute-hand&quot; class=&quot;minute-hand&quot;&gt;
    &lt;div class=&quot;white-space&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div id=&quot;second-hand&quot; class=&quot;second-hand&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;center&quot;&gt;&lt;/div&gt;
&lt;/div&gt;</code></pre>
<p>style.css</p>
<pre><code class="language-css">.hour-hand {
  position: absolute;
  bottom: calc(50% - 10px);
  left: calc(50% - 10px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  width: 20px;
  height: 200px;
  background-color: #000000;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  transform: rotate(45deg);
  transform-origin: center 190px;
  z-index: 3;
}

.hour-hand::before {
  content: &#39;&#39;;
  position: absolute;
  top: -20px;
  width: 0;
  height: 0;
  border-right: 10px solid transparent;
  border-bottom: 20px solid black;
  border-left: 10px solid transparent;
}

.minute-hand {
  position: absolute;
  bottom: calc(50% - 10px);
  left: calc(50% - 8px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  width: 16px;
  height: 250px;
  background-color: #000000;
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  transform: rotate(180deg);
  transform-origin: center 240px;
  z-index: 3;
}

.minute-hand::before {
  content: &#39;&#39;;
  position: absolute;
  top: -30px;
  width: 0;
  height: 0;
  border-right: 8px solid transparent;
  border-bottom: 32px solid black;
  border-left: 8px solid transparent;
}

.second-hand {
  position: absolute;
  bottom: calc(50% - 30px);
  left: calc(50% - 1px);
  width: 2px;
  height: 320px;
  background-color: orangered;
  transform: rotate(300deg);
  transform-origin: center 290px;
  z-index: 3;
}

.white-space {
  width: 50%;
  height: 80%;
  margin-bottom: 30px;
  background-color: #ffffff;
}

.center {
  position: absolute;
  top: calc(50% - 5px);
  left: calc(50% - 5px);
  width: 10px;
  height: 10px;
  background-color: #ffffff;
  border-radius: 50%;
  z-index: 4;
}</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/21c9c767-0075-45cd-8e6a-6420a4cd377b/image.png" alt=""></p>
<br>

<h2 id="✔-바늘-회전시키기">✔ 바늘 회전시키기</h2>
<p>우선 바늘들의 모습을 확인하기 위해서 각 속성에 적용했던 transform:rotate() 속성들을 지우고</p>
<p>바늘들을 어떻게 회전시킬지 오래 고민하다가 내린 결론은 Date 객체로 현재 시간을 받아서 바늘들의 현재 위치만 정해주면 애니메이션의 duration값에 따라서 바늘들이 속도를 달리해서 움직일 수 있겠다는 거였다.</p>
<p>그러기 위해선 애니메이션의 from값과 to값에 javascript로 값을 대입해야 했는데 애니메이션을 javascript로 조작 가능한지 몰랐다.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/animate">MDN - Element.animate()</a></p>
<p>문서를 읽어보니 Element.animate()를 이용해서 애니메이션을 설정할 수 있다는 걸 확인하고 적용했다.</p>
<p>각도 계산하는 것도 단위 변환등 고려해야 될게 많았다... 헷갈려서 각도 구하는 것만 하루종일 잡고 있었던 것 같다...</p>
<p>script.js</p>
<pre><code class="language-javascript">const hour = document.getElementById(&#39;hour-hand&#39;);
const minute = document.getElementById(&#39;minute-hand&#39;);
const second = document.getElementById(&#39;second-hand&#39;);

const date = new Date();

// 시침, 분침, 초침 현재 위치 각도 계산
const secDeg = (360 * (date.getSeconds() / 60)) + (6 * (date.getMilliseconds() / 1000));
const minDeg = (360 * (date.getMinutes() / 60)) + (6 * (secDeg / 360));
const hourDeg = (360 * (date.getHours() / 12)) + (30 * (minDeg / 360));

// 시침, 분침, 초침 rotate 적용 함수
function rotateAnimation(hand, duration, deg) {
  hand.animate([
    { transform: `rotate(${deg}deg)` },
    { transform: `rotate(${deg + 360}deg)` }
  ], {
    duration: duration,
    iterations: Infinity
  });
}

rotateAnimation(hour, 43200000, hourDeg);
rotateAnimation(minute, 3600000, minDeg);
rotateAnimation(second, 60000, secDeg);</code></pre>
<br>

<h1 id="🚩-완성">🚩 완성</h1>
<p><a href="https://1k3h.github.io/clock/">결과물 확인 링크</a></p>
<p><a href="https://github.com/1K3H/clock">전체 코드 링크</a></p>
<p><img src="https://images.velog.io/images/home_2201/post/d3a34280-f328-46d5-b30c-847ddbb682a5/image.png" alt=""></p>
<br>

<h1 id="🤔-후기">🤔 후기</h1>
<p>그리기에 특화된 것 같은 svg나 canvas를 이용하면 좀 더 손쉬운 방법으로 만들 수 있지 않았을까...</p>
<p>시계를 만들었으니 이 프로젝트를 활용해서 알람, 스탑워치, 세계시간 같은 기능도 추가할 수 있지 않을까...</p>
<p>코딩 하는데 수학 중요하지 않다던 사람들 그거 다 거짓말이야...</p>
<p>일단 완성했으니 뿌듯하다</p>
<br>

<h1 id="개선할-부분-참고할-자료-등등-피드백-환영합니다">개선할 부분, 참고할 자료 등등 피드백 환영합니다~</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[지뢰 찾기를 만들자 (HTML, CSS, JS)]]></title>
            <link>https://velog.io/@home_2201/JS%EB%A1%9C-%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@home_2201/JS%EB%A1%9C-%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sat, 21 Nov 2020 17:01:19 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/1K3H/minesweeper">github - 전체 코드</a>
<br>
<br></p>
<h1 id="💡-발단">💡 발단</h1>
<br>

<ul>
<li><p>온라인으로 JS에 관한 튜토리얼 강의들을 들으며 깨달은 점은 튜토리얼의 내용을 따라서 코드를 완성하고 나면 튜토리얼을 완주한 것에서 오는 성취감은 크지만 튜토리얼에 나오는 내용을 내 것으로 체득? 했다고 말하기는 쉽지 않다는 것이었다. 그래서 지금까지 배운 문법을 토대로 나혼자 뭐든 만들어보자는 생각을 갖고 있었다.</p>
</li>
<li><p>어떤 것을 구현해볼까 찾아보던 중 우연히 지뢰찾기를 발견했고 평소에는 별로 관심이 없던 지뢰찾기에 갑자기 빠져서 한동안 지뢰찾기를 플레이 하다가 &#39;이정도는 내가 구현할 수 있지 않을까?&#39;하는 생각에 지뢰찾기를 만들기로 했다</p>
</li>
</ul>
<br>
<br>

<hr>
<h1 id="🔎-지뢰-찾기-살펴보기">🔎 &#39;지뢰 찾기&#39; 살펴보기</h1>
<br>

<ul>
<li>베이스는 컴퓨터에 있는 &#39;Microsoft Minesweeper&#39;의 &#39;주문제작&#39; 부분으로 했다.<br></li>
<li>게임방법</li>
</ul>
<p><img src="https://images.velog.io/images/home_2201/post/798e5879-fb60-4803-befa-5fa1a47d8641/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%EA%B2%8C%EC%9E%84%ED%8C%90%20%EC%84%A4%EC%A0%95.png" alt="">
먼저 보드의 크기와 보드에 들어갈 지뢰의 개수를 설정한다. 그리고 게임 시작 버튼을 누르면
<img src="https://images.velog.io/images/home_2201/post/9a968e28-9629-4c69-93e6-c6360f1bd1c5/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%ED%83%80%EC%9D%BC.png" alt="">
이렇게 보드가 생성된다.
<img src="https://images.velog.io/images/home_2201/post/695c58b4-e224-4a4a-b98f-c41fa87b02d4/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%ED%83%80%EC%9D%BC%20%EC%84%A4%EB%AA%85.png" alt="">
각 타일들을 클릭하면 지뢰의 유무나 주변 타일의 지뢰 유무에 따라 타일에 표시되는 정보가 다른데 정리해보면</p>
<p><strong>주변 타일</strong>: 클릭한 타일을 기준으로 상, 하, 좌, 우 한 칸씩 그리고 좌상, 우상, 좌하, 우하 대각으로 한 칸씩</p>
<p><strong>마우스 좌 클릭</strong></p>
<ul>
<li><strong>지뢰 타일</strong>: 선택시 게임종료</li>
<li><strong>숫자 정보가 담긴 타일</strong>: 주변 타일에 지뢰가 몇개 있는지 표시</li>
<li><strong>하얀색 타일</strong>: 주변 타일에 지뢰가 전혀 없다는 의미. 이 타일을 선택하면 주변 타일 중 숫자 정보가 담긴 타일은 함께 표시하고 만약 주변 타일에 자신과 같은 하얀 타일이 있다면 이 타일도 동시에 같은 작업을 수행함</li>
</ul>
<p><strong>마우스 우 클릭</strong></p>
<ul>
<li><strong>깃발 타일</strong>: 숫자 타일을 토대로 지뢰 타일이라고 확신할 수 있는 타일을 사용자가 설정할 수 있다(우 클릭 1회)</li>
<li><strong>물음표 타일</strong>: 지뢰 타일인지 아닌지 확신할 수 없을 때 사용(깃발 타일 상태에서 우 클릭시 사용가능)</li>
</ul>
<p><strong>마우스 좌우 동시 클릭 or 마우스 휠 클릭</strong></p>
<p>숫자 타일을 마우스로 좌우 동시 클릭 하거나 휠 클릭 하면 주변 타일들 중 비활성화된 타일들(어떤 정보도 갖고 있지 않은 타일들)을 표시한다. 이 과정에서 숫자 타일의 주변 타일에 숫자 타일의 숫자 만큼의 깃발 타일이 존재한다면 비활성화되어 있는 타일들은 자동으로 작동하게 된다.
<img src="https://images.velog.io/images/home_2201/post/67f9653e-2b8c-4241-a9a0-e9dc6b5fa7b4/%EC%A2%8C%EC%9A%B0%20%EB%8F%99%EC%8B%9C%20%ED%81%B4%EB%A6%AD.png" alt="">
숫자 &#39;2&#39; 타일 선택 시 비활성 중인 타일 어둡게 표시 &gt; 깃발 타일의 개수가 2개 이므로 비활성 타일 자동으로 작동
<br>
<br></p>
<hr>
<h1 id="💻-기능-구현하기">💻 기능 구현하기</h1>
<br>
<br>

<h2 id="1-입력값을-받아서-보드-만들기">1. 입력값을 받아서 보드 만들기</h2>
<p>우선 일정한 크기의 타일을 갖는 보드를 생성하기 위해서 어떻게 해야될지 고민을 하다가 html의 table을 이용하면 될 것 같다는 생각을 했다.</p>
<p>html파일에 input태그를 만들고 가로 길이와 세로 길이의 입력값을 받아서 table을 만들면 될 것 같다고 생각은 했는데 그 과정을 코드로 어떻게 짜야 되는지 몰라서 검색을 해봤다.</p>
<p><a href="https://lasdri.tistory.com/594">티스토리 Wallel - JavaScript 동적테이블 생성(행, 열 입력받아서)</a></p>
<p>index.html</p>
<pre><code>&lt;body&gt;
    &lt;div id=&quot;gameBoard&quot;&gt;
        &lt;input type=&quot;number&quot; id=&quot;row&quot; placeholder=&quot;가로&quot;&gt;
        &lt;input type=&quot;number&quot; id=&quot;col&quot; placeholder=&quot;세로&quot;&gt;
        &lt;button id=&quot;startBtn&quot;&gt;게임 시작&lt;/button&gt;
    &lt;/div&gt;
    &lt;script src=&quot;program.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;</code></pre><p>program.js</p>
<pre><code class="language-javascript">const startBtn = document.getElementById(&quot;startBtn&quot;);
startBtn.addEventListener(&quot;click&quot;, setGame);

function setGame() {
  const row = parseInt(document.getElementById(&quot;row&quot;).value);
  const col = parseInt(document.getElementById(&quot;col&quot;).value);

  makeBoard(row, col);

  function makeBoard(rowNum, colNum) {
    let tableEle = &#39;&lt;table&gt;&#39;;

    for (let i = 0; i &lt; colNum; i++) {
      tableEle += &#39;&lt;tr&gt;&#39;;
      for (let j = 0; j &lt; rowNum; j++) {
        tableEle += &#39;&lt;td&gt;&lt;/td&gt;&#39;
      }
      tableEle += &#39;&lt;/tr&gt;&#39;;
    }
    tableEle += &#39;&lt;/table&gt;&#39;;
    document.getElementById(&quot;gameBoard&quot;).innerHTML = tableEle;
  }  
}</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/9a090d36-ad24-4e79-8124-39404009247c/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%EC%84%A4%EC%A0%95%ED%99%94%EB%A9%B4.png" alt="">
<img src="https://images.velog.io/images/home_2201/post/70f69921-cd65-4e01-a3e6-3af211bdce5c/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%EB%B3%B4%EB%93%9C%EC%83%9D%EC%84%B1.png" alt=""></p>
<h3 id="✔-parseint"><strong>✔ parseInt()</strong></h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/parseInt">MDN - parseInt()</a></p>
<p>documet.getElementById().value를 사용해 input태그의 입력값을 가져오면 typeof로 확인 시 string 타입인 것을 확인할 수 있다. 입력값을 다른 식에서 활용하기 위해선 값을 number 타입으로 바꿔줘야 되는데 그럴 때 parseInt()를 이용해서 변환이 가능하다.</p>
<h3 id="✔-중첩-반복문"><strong>✔ 중첩 반복문</strong></h3>
<p>table 태그에서는 tr 태그로 묶인 td 태그들이 한 개의 열을 구성한다. 위의 코드를 풀어보면 처음 for 반복문에서 tr 태그로 처음 열을 시작하고 다음 for 반복문을 통해 행을 추가한 다음 반복이 끝나면 처음의 반복문으로 돌아가 /tr 태그로 시작했던 열을 닫고 다음 열을 시작하는 과정을 반복한다.</p>
<p>(반복문 사용이 익숙하지 않아서 초깃값 설정과 반복 조건을 통해서 얼만큼 반복을 해야되는지 설정하는 부분에서 애를 좀 먹었다.)</p>
<h3 id="✔-innerhtml"><strong>✔ innerHTML</strong></h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/API/Element/innerHTML">MDN - Element.innerHTML</a></p>
<p>innerHTML 의 값을 설정(대입)하면 요소의 모든 자손이 제거되고, 문자열 htmlString에 지정된 HTML을 파싱하고, 생성된 노드로 대체합니다.
<br>
<br></p>
<hr>
<h2 id="2-입력값을-범위로-하는-중복-없는-난수-만들기지뢰-위치-설정">2. 입력값을 범위로 하는 중복 없는 난수 만들기(지뢰 위치 설정)</h2>
<p>게임 이름이 &#39;지뢰 찾기&#39;인 만큼 게임 기능 구현에 있어서 보드의 어느 위치에 지뢰를 위치하게 할 것인지 설정하는 것이 중요한 요소인 것 같았다. 각각의 타일에 &#39;지뢰&#39;라는 개념을 어떻게 넣을 것인지 모르는 상태에서 우선 지뢰에 해당하는 위치를 나타내는 숫자들의 그룹을 만들어야 겠다는 생각을 했다.</p>
<p>사용해 봤던 Math.random()과 Math.floor()를 사용해서 번호를 뽑아봤는데 그렇게 나온 결과를 보고 있으니 중복되는 값이 존재했다. 중복값이 존재하면 입력값으로 받은 범위에 못 미치는 지뢰개수를 갖게 된다.</p>
<p>중복값 없이 Math.random()과 Math.floor()의 결괏값을 얻을 수 없을까 검색!</p>
<p><a href="https://im-developer.tistory.com/101">티스토리 Code Playground - 중복값 없는 랜덤 숫자 추출하는 여러가지 방법</a></p>
<p>index.html</p>
<pre><code class="language-html">&lt;body&gt;
  &lt;div id=&quot;gameBoard&quot;&gt;
    ...
    &lt;input type=&quot;number&quot; id=&quot;mineNum&quot; placeholder=&quot;지뢰 개수&quot;&gt;
    ...
  &lt;/div&gt;
  ...
&lt;/body&gt;</code></pre>
<p>program.js</p>
<pre><code class="language-javascript">const startBtn = document.getElementById(&quot;startBtn&quot;);
startBtn.addEventListener(&quot;click&quot;, setGame);

function setGame() {
  const row = parseInt(document.getElementById(&quot;row&quot;).value);
  const col = parseInt(document.getElementById(&quot;col&quot;).value);
  const mineNum = parseInt(document.getElementById(&quot;mineNum&quot;).value);

  makeBoard(row, col);
  setMineNumArr(mineNum, row * col);
}

function makeBoard(rowNum, colNum) {...}  

function setMineNumArr(numLimit, numRange) {
  mines = [];
  for (let i = 0; i &lt; numLimit; i++) {
    let randomNum = Math.floor(Math.random() * numRange);
    if (!findMine(randomNum)) {
      mines.push(randomNum);
    } else {
      i--;
    }
  }
  function findMine(j) {
    return mines.find((e) =&gt; (e === j));
  }
}</code></pre>
<h3 id="✔-화살표-함수">✔ 화살표 함수</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/%EC%95%A0%EB%A1%9C%EC%9A%B0_%ED%8E%91%EC%85%98">MDN - Arrow function(화살표 함수)</a></p>
<pre><code class="language-javascript">//기존 함수 표현식
function(e) { return e === j };

//화살표 함수 표현식
(e) =&gt; { return e === j };
//인수가 하나만 있으면 인수를 묶는 괄호를 생략할 수 있다.
e =&gt; { return e === j };
//함수 몸통 안의 문장이 return뿐이면 중괄호와 return 키워드 생략가능
//but 반환값이 객체 리터럴이면 ()로 묶어야함
e =&gt; e === j;

//출처: 도서 &#39;모던 자바스크립트 입문&#39;  </code></pre>
<h3 id="✔-함수의-결괏값을-조건문의-조건으로-사용하기">✔ 함수의 결괏값을 조건문의 조건으로 사용하기</h3>
<h3 id="✔-arraypush-arrayfind">✔ Array.push(), Array.find()</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/push">MDN - Array.prototype.push()</a>
<a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/find">MDN - Array.prototype.find()</a></p>
<p>Array 메서드 다시 한 번 훑어보기</p>
<h3 id="🔨-mines에-선언자-없이-전역-변수로-사용한-부분-수정">🔨 mines에 선언자 없이 전역 변수로 사용한 부분 수정</h3>
<pre><code class="language-javascript">function setGame() {
  const row = parseInt(document.getElementById(&quot;row&quot;).value);
  const col = parseInt(document.getElementById(&quot;col&quot;).value);
  const mineNum = parseInt(document.getElementById(&quot;mineNum&quot;).value);
  const mineArr = setMineNumArr(mineNum, row * col);

  makeBoard(row, col);
  //setMineNumArr(mineNum, row * col);
}

function setMineNumArr(numLimit, numRange) {
  let mineArr = [];
  for (let i = 0; i &lt; numLimit; i++) {
    let randomNum = Math.floor(Math.random() * numRange);
    if (!findMine(randomNum)) {
      mineArr.push(randomNum);
    } else {
      i--;
    }
  }
  function findMine(j) {
    return mineArr.find((e) =&gt; (e === j));
  }
  return mineArr;
}</code></pre>
<p>지뢰의 위치가 담긴 배열을 만들고 다른 함수에서 그 배열을 이용하기 위해 고민하다가 변수 선언 시 선언자를 쓰지 않으면 전역 변수로 사용 가능하다는 것을 알고 선언자 없이 사용했지만 이런 방법으로 변수를 선언하면 변수의 충돌을 일으킬 수 있어서 좋은 방법이 아니라는 걸 배우고 함수에서 완성된 배열을 return으로 반환하여 그 값을 새로운 변수로 저장하게끔 바꿈
<br>
<br></p>
<hr>
<h2 id="3-보드에-지뢰-세팅하기">3. 보드에 지뢰 세팅하기</h2>
<p>지뢰가 위치할 번호를 뽑아서 배열에 담아뒀으니 이제 이 배열을 이용해서 만들어진 보드에 지뢰를 담는 과정을 진행해야 했다. mines 배열을 만들면서 사용된 배열을 돌며 해당 요소가 배열에 있는지 확인하는 작업을 통해서 보드에도 같은 작업을 하면 될 것 같다는 생각을 했는데 문제는 보드를 만드는 함수를 통해 만들어진 table 안의 요소에 접근해서 그 요소들을 배열에 담는 방법이 생각보다 까다롭다는 점이었다.</p>
<p>js에서 html요소에 접근하는 방법으로 알고 있던 것들은 각 요소의 id나 class를 getElementById() 또는 getElementByClass()로 불러오는 법 뿐이었는데 그러려면 보드를 만드는 반복문 내용중 td태그를 삽입하는 과정에 id나 class를 추가하는 작업을 진행해야 했다.</p>
<p>그렇게 td 요소에 선택자를 추가하는 방법으로 작업을 진행하던 와중에 vscode에서 getElementBy를 치면 자동완성으로 생성되는 목록에 getElementByTagName이 있는 걸 발견하고 이름만 봤을 때 &#39;html의 요소를 태그 별로 꺼낼 수 있는 건가?&#39; 싶어서 검색을 해봤다.  </p>
<h3 id="✔-getelementbytagname-htmlcollection">✔ getElementByTagName(), HTMLCollection</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName">MDN - Document.getElementsByTagName()</a>
설명을 읽어보니 html파일에서 tag를 한 번에 불러와서 무려 배열 형태의 객체인 HTMLCollection 쓸 수 있다고 한다.(HTMLcollection은 배열의 모습을 하고 있지만 배열 메서드를 사용할 수 없다.)</p>
<p>getElementByTagName(&#39;td&#39;)를 통해 생성된 td요소를 모두 불러와서 변수에 저장하고 이제 이 요소를 반복문을 통해 mines배열과 내부 요소를 비교하며 일치하는 위치에 mine이라는 class를 추가하면 원하는 결과를 얻을 수 있을 것 같다.</p>
<h3 id="✔-elementclasslist">✔ Element.classList</h3>
<p><a href="https://jamesdreaming.tistory.com/21">티스토리 Dev Life in IT - Javascript class 명 추가/삭제</a>
<a href="https://developer.mozilla.org/ko/docs/Web/API/Element/classList">MDN - Element.classList</a></p>
<p>program.js</p>
<pre><code class="language-javascript">...
const tdArr = document.getElementsByTagName(&#39;td&#39;);


function setGame() {
  const row = parseInt(document.getElementById(&quot;row&quot;).value);
  const col = parseInt(document.getElementById(&quot;col&quot;).value);
  const mineNum = parseInt(document.getElementById(&quot;mineNum&quot;).value);
  const mineArr = setMineNumArr(mineNum, row * col);

  makeBoard(row, col);

  putMineInBoard(mineArr);
}

function makeBoard(rowNum, colNum) {...}  

function setMineNumArr(numLimit, numRange) {
  let mineArr = [];
  for (let i = 0; i &lt; numLimit; i++) {
    let randomNum = Math.floor(Math.random() * numRange);
    if (!findMine(randomNum)) {
      mineArr.push(randomNum);
    } else {
      i--;
    }
  }
  function findMine(j) {
    return mineArr.find((e) =&gt; (e === j));
  }
  return mineArr;
}

function putMineInBoard(mine) {
  for (let i = 0; i &lt; tdArr.length; i++) {
    if (findMine(i)) {
      tdArr[i].classList.add(&#39;mine&#39;);
    }
  }
  function findMine(j) {
    return mine.find((e) =&gt; (e === j));
  }
}
</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/915d95e8-f831-446f-86f5-088d01f6cfa3/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%EC%A7%80%EB%A2%B0%20%EC%84%B8%ED%8C%85.png" alt="">
<img src="https://images.velog.io/images/home_2201/post/c4c319c5-b85d-47c7-b502-c4ced4832aaa/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%EC%A7%80%EB%A2%B0%20%EC%84%A4%EC%B9%98.png" alt="">
지뢰가 보드에 잘 자리 잡았다!!!
<br>
<br></p>
<hr>
<h2 id="4-보드의-가로-세로-입력값에-따라-각-타일의-위치를-특정할-수-있는-식-세우기">4. 보드의 가로, 세로 입력값에 따라 각 타일의 위치를 특정할 수 있는 식 세우기</h2>
<p>보드의 크기가 고정된 형태로 게임을 구현하면 문제가 되지 않겠지만 보드의 크기를 입력값을 받아서 만들기 때문에 그에 따라 타일의 개수가 달라지고 그래서 타일의 위치를 파악할 수 있는 방법이 필요하다.
<img src="https://images.velog.io/images/home_2201/post/512ce15f-f4fa-40f4-8ca7-2534638e4dca/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%ED%83%80%EC%9D%BC%20%EC%9C%84%EC%B9%98.png" alt="">
가로를 x 세로를 y 라고 잡았을 때 
이런 식으로 대략적인 기준을 잡고 오른쪽으로 한 칸 이동하면 +1씩 아래칸으로는 +x씩 늘어난다는 정도만 잡아 놓으면 될 것 같다.</p>
<p>각 코너의 수들은 식으로 특정할 수 있지만 그 사이에 존재하는 칸들은 그 수가 변하기 때문에 반복문을 통해서 시작부분과 끝부분을 정하고 +1 혹은 +x를 해주면 될 것 같다.</p>
<p><strong>위쪽 모서리</strong>: 1부터 시작 x-2까지 1씩 증가
<strong>아래쪽 모서리</strong>: xy-x부터 시작 xy-2까지 1씩 증가
<strong>왼쪽 모서리</strong>: x부터 시작 xy-2x까지 x만큼씩 증가
<strong>오른쪽 모서리</strong>: 2x-1부터 시작 xy-x-1까지 x만큼씩 증가</p>
<p>(getElementByClassName으로 만든 tdArr 변수에서 첫 번째 td는 tdArr.[0]칸에 위치해 있기 때문에 0번부터 시작하도록 만든다.)</p>
<br>
<br>

<hr>
<h2 id="5-주변-타일들-배열로-만들기">5. 주변 타일들 배열로 만들기</h2>
<p>타일을 선택했을 때 선택한 타일을 둘러싼 주변 타일들이 어떤 종류의 타일인지에 따라서 선택한 타일에서 실행할 내용이 달라진다.</p>
<p>이런 구분을 하기 위해선 우선적으로 특정 타일을 선택했을때의 주변 타일들을 그룹화 할 필요가 있었고 그 방법으로 배열에 담기로 했다.</p>
<p>주변 타일을 배열에 담는 작업을 하다보니 선택한 타일의 위치에 따라서 주변 타일의 개수와 관계식에 차이가 있었다.
<img src="https://images.velog.io/images/home_2201/post/671e4f63-410b-4d8c-9d08-c9d2dce61439/%EC%A7%80%EB%A2%B0%EC%B0%BE%EA%B8%B0%20%EB%B3%B4%EB%93%9C%EC%83%9D%EC%84%B1.png" alt="">
🟥: 선택한 타일(N) / 🟦: 주변 타일 / x : 보드 가로 길이</p>
<p><strong>각 코너 선택 시 주변 타일 그룹</strong></p>
<p>왼쪽 위: [N+1, N+x, N+x+1]
오른쪽 위: [N-1, N+x-1, N+x]
왼쪽 아래: [N-x, N-x+1, N+1]
오른쪽 아래: [N-x-1, N-x, N-1]</p>
<p><strong>각 모서리 선택 시 주변 타일 그룹</strong></p>
<p>위쪽: [N-1, N+1, N+x-1, N+x, N+x+1]
아래쪽: [N-x-1, N-x, N-x+1,N-1, N+1]
왼쪽: [N-x, N-x+1, N+1, N+x, N+x+1]
오른쪽: [N-x-1, N-x, N-1, N+x-1, N+x]</p>
<p><strong>나머지 타일들 선택 시 주변 타일 그룹</strong></p>
<p>[N-x-1, N-x, N-x+1, N-1, N+1, N+x-1, N+x, N+x+1]
<br>
<br></p>
<hr>
<h2 id="6-각-타일에-클릭-시-실행할-함수-등록하기">6. 각 타일에 클릭 시 실행할 함수 등록하기</h2>
<pre><code class="language-javascript">function tileEvent(mine ,targetNum, ...aroundArr) {
  tdArr[targetNum].addEventListener(&quot;click&quot;, function () {
    let count = 0;
    for (let i = 0; i &lt; aroundArr.length; i++) {
      if (findMine(aroundArr[i])) {
        count++
      }
    }

    function findMine(j) {
      return mine.find((e) =&gt; (e === j));
    }

    if (tdArr[targetNum].className === &#39;mine&#39;) {
      alert(&#39;GAME OVER!!!&#39;)
    } else if (count === 0) {
      tdArr[targetNum].style.backgroundColor = &quot;darkcyan&quot;;
      for (let i = 0; i &lt; aroundArr.length; i++) {
        tdArr[aroundArr[i]].click();
      }
    } else {
      tdArr[targetNum].innerHTML = count;
    }
  });
}</code></pre>
<p>타일을 클릭 했을 때 어떤 작동을 할 지 세가지로 분류했다.</p>
<ol>
<li><p>클릭한 타일이 class에 mine이 있을 때 = 지뢰 타일 =&gt; 게임 종료</p>
</li>
<li><p>count(주변타일에 있는 지뢰 개수)가 0일 때 = 아무 정보 없는 타일 =&gt; 주변 타일 모두 실행</p>
</li>
<li><p>count가 0이 아닐 때 = 숫자 타일 =&gt; 클릭한 타일에 count를 출력</p>
</li>
</ol>
<p>함수를 생성하고 나서 각 코너, 모서리, 나머지 타일들 그룹별로 함수를 각각 실행했다.</p>
<pre><code class="language-javascript">  // 좌상
  tileEvent(mineArr, 0, 1, row, row+1);
  // 우상
  tileEvent(mineArr, row-1, row-2, 2*row-2, 2*row-1);
  // 좌하
  tileEvent(mineArr, row * (col-1), row*(col-2), row*(col-2)+1, row*(col-1)+1);
  // 우하
  tileEvent(mineArr, row*col-1, row*(col-1)-2, row*(col-1)-1, row*col-2);

  // 모서리 타일
  // 상
  for (let i = 1; i &lt;= row-2; i++) {
    tileEvent(mineArr, i, i-1, i+1, i+row-1, i+row, i+row+1);
  }
  // 하
  for (let i = row*(col-1)+1; i &lt;= row*col-2; i++) {
    tileEvent(mineArr, i, i-row-1, i-row, i-row+1, i-1, i+1);
  }
  // 좌
  for (let i = row; i &lt;= row*(col-2); i += row) {
    tileEvent(mineArr, i, i-row, i-row+1, i+1, i+row, i+row+1);
  }
  // 우
  for (let i = 2*row-1; i &lt;= row*(col-1)-1; i += row) {
    tileEvent(mineArr, i, i-row-1, i-row, i-1, i+row-1, i+row);
  }

  // 나머지 모든 타일
  for (let i = 1; i &lt;= col-2; i++) {
    for (let j = i*row+1; j &lt;= (1+i) * row-2; j++) {
      tileEvent(mineArr, j, j-row-1, j-row, j-row+1, j-1, j+1, j+row-1, j+row, j+row+1);
    }
  }</code></pre>
<h3 id="✔-rest-파라미터">✔ Rest 파라미터</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/rest_parameters">MDN - Rest 파라미터</a>
코너, 모서리, 중앙 모두 각각의 주변 타일 그룹이 필요한데 배열을 다 따로 생성한 다음에 함수에 넣어야 하나 생각하고 있었는데 검색하다가 Rest 파라미터를 발견하고 바로 적용해 봤다.</p>
<h3 id="🔨-변수의-유효-범위는-생각보다-많이-중요하다">🔨 변수의 유효 범위는 생각보다 많이 중요하다.</h3>
<p>for 반복문을 처음 배울 때 변수를 초기화하는 부분에서 선언자 없이 그냥 쓴다고 잘못 기억하고선 지금까지 for 반복문을 쓸 때 선언자 없이 변수를 선언해왔다. 지금까지는 코드에 반복문을 여러 번 쓸 일이 없었기 때문에 괜찮았지만 이번에는 달랐다.</p>
<p>tileEvent 함수를 작성하고 나서 실행했을 때 원하는 결과가 안나와서 한 3일 동안을 그 부분을 해결한다고 골치를 썩었다. 도저히 혼자서는 답이 안나올 것 같아서 문제가 되는 부분을 <strong>wecode community</strong>에 질문 했는데 날아오는 답변 모두 &#39;for 반복문 변수 선언에 선언자가 없어서 그런 것 같은데요?&#39; 였다. </p>
<p>문제가 되는 부분 뿐만 아니라 그 위에서 부터 for 반복문을 쓸 때 모두 선언자 없이 변수 선언을 했기 때문에 변수가 어디서 어떻게 오염된 건지 찾기도 힘들 것 같았다.</p>
<p>결국 선언자 없이 변수를 선언했던 for 반복문에 전부 let 선언자를 추가하고 나서야 원하는 방향으로 코드가 돌아가기 시작했다.</p>
<h3 id="🔨-find를-indexof로-대체하기">🔨 find()를 indexOf()로 대체하기</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf">MDN - Array.prototype.indexOf()</a></p>
<pre><code class="language-javascript">function setMineNumArr(numLimit, numRange) {
  let mineArr = [];
  for (let i = 0; i &lt; numLimit; i++) {
    let randomNum = Math.floor(Math.random() * numRange);
    if (mineArr.indexOf(randomNum) === -1) {
      mineArr.push(randomNum);
    } else {
      i--;
    }
  }
  return mineArr;
}

function putMineInBoard(mine) {
  for (let i = 0; i &lt; tdArr.length; i++) {
    if (mine.indexOf(i) !== -1) {
      tdArr[i].classList.add(&#39;mine&#39;);
    }
  }
}

function tileEvent(mine ,targetNum, ...aroundArr) {
  tdArr[targetNum].addEventListener(&quot;click&quot;, function () {
    let count = 0;
    for (let i = 0; i &lt; aroundArr.length; i++) {
      if (mine.indexOf(aroundArr[i]) !== -1) {
        count++
      }
    }
    if (tdArr[targetNum].className === &#39;mine&#39;) {
      alert(&#39;GAME OVER!!!&#39;)
    } else if (count === 0) {
      tdArr[targetNum].style.backgroundColor = &quot;darkcyan&quot;;
      for (let i = 0; i &lt; aroundArr.length; i++) {
        tdArr[aroundArr[i]].click();
      }
    } else {
      tdArr[targetNum].innerHTML = count;
    }
  });
}</code></pre>
<br>
<br>

<hr>
<h2 id="7-마우스-우-클릭-기능-구현하기">7. 마우스 우 클릭 기능 구현하기</h2>
<p>우 클릭 &gt; 깃발 &gt; 우 클릭 &gt; 물음표 &gt; 우 클릭 &gt; 원래 상태로</p>
<p>우 클릭 이벤트 리스너로 깃발과 물음표를 넣는 건 별로 어렵지 않을 것 같다. 문제는 우 클릭으로 타일을 깃발 타일과 물음표 타일로 만들었을 때 바꿔줘야 될 부분이 있다.</p>
<ul>
<li>깃발 타일에서 물음표 타일로 넘어가는 과정은 어떻게 구현할까?<br>
- 맨 처음 비활성된 타일을 우 클릭하면 깃발 타일이 된다.
- 우 클릭시 기본으로 실행되는 메뉴를 없애기도 해야함(contextmenu, preventDefault) 
- 깃발 타일이 된 상태에서는 우 클릭을 했을 때 물음표 타일이 된다.
- 그럼 우 클릭 이벤트를 실행할 때 해당 타일이 비활성화된 타일인지 깃발 타일로 변경된 타일인지 구분할 필요가 있다
<br></li>
<li>깃발 타일과 물음표 타일로 변환시 해당 타일에 설정된 좌 클릭 이벤트를 삭제해야한다. (깃발 타일과 물음표 타일은 좌 클릭에 반응하지 않도록)<br>
- 좌 클릭 이벤트를 삭제하는 대신에 좌 클릭 이벤트에 등록한 함수에 조건을 추가해서 우 클릭을 통해 추가된 class를 감지해 그 조건에서는 기능이 실행되지 않도록 구현




</li>
</ul>
<pre><code class="language-javascript">function tileEvent(mine, targetNum, ...aroundArr) {
  tdArr[targetNum].addEventListener(&quot;click&quot;, function () {
    if (tdArr[targetNum].className !== &#39;flag&#39; &amp;&amp; 
      tdArr[targetNum].className !== &#39;qmark&#39; &amp;&amp;
      tdArr[targetNum].className !== &#39;mine flag&#39; &amp;&amp; 
      tdArr[targetNum].className !== &#39;mine qmark&#39;) {
      let count = 0;
      for (let i = 0; i &lt; aroundArr.length; i++) {
        if (mine.indexOf(aroundArr[i]) !== -1) {
          count++
        }
      }
      if (tdArr[targetNum].className === &#39;mine&#39;) {
        alert(&#39;GAME OVER!!!&#39;)
      } else if (count === 0) {
        tdArr[targetNum].style.backgroundColor = &quot;darkcyan&quot;;
        for (let i = 0; i &lt; aroundArr.length; i++) {
          tdArr[aroundArr[i]].click();
        }
      } else {
        tdArr[targetNum].innerHTML = count;
      }
    }
  });

  tdArr[targetNum].addEventListener(&quot;auxclick&quot;, function () {
    tdArr[targetNum].addEventListener(&quot;contextmenu&quot;, function (e) {
      e.preventDefault();
    });

    if (tdArr[targetNum].className === &#39;flag&#39; ||
      tdArr[targetNum].className === &#39;mine flag&#39;) {
      tdArr[targetNum].classList.remove(&#39;flag&#39;);
      tdArr[targetNum].classList.add(&#39;qmark&#39;);
      tdArr[targetNum].innerHTML = &#39;❓&#39;
    } else if (tdArr[targetNum].className === &#39;qmark&#39; ||
      tdArr[targetNum].className === &#39;mine qmark&#39;) {
      tdArr[targetNum].classList.remove(&#39;qmark&#39;);
      tdArr[targetNum].innerHTML = &#39;&#39;;
    } else {
      tdArr[targetNum].classList.add(&#39;flag&#39;);
      tdArr[targetNum].innerHTML = &#39;🚩&#39;;
    }
  });
}</code></pre>
<h3 id="✔-auxclick">✔ auxclick</h3>
<p>JS의 이벤트에 우 클릭에 해당하는 이벤트는 따로 없는 것 같다. auxclick이라는 이벤트는 (click 이벤트가 좌 클릭에 해당하는 것에 반해서) 좌 클릭을 제외한 마우스의 클릭 이벤트를 의미한다.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event">MDN - Element: auxclick event</a></p>
<h3 id="✔-contextmenu-preventdefault">✔ contextmenu, preventDefault()</h3>
<p>페이지 상에서 우 클릭시 기본적으로 실행되는 기능을 없앨 방법이 필요했다.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event">MDN - Element: contextmenu event</a>
<a href="https://developer.mozilla.org/ko/docs/Web/API/Event/preventDefault">MDN - event.preventDefault</a></p>
<pre><code class="language-javascript">noContext = document.getElementById(&#39;noContextMenu&#39;);

noContext.addEventListener(&#39;contextmenu&#39;, e =&gt; {
  e.preventDefault();
});</code></pre>
<br>
<br>

<hr>
<h2 id="8-주변-타일-중-깃발-타일-개수와-지뢰-타일-개수가-같을-때-숫자타일-클릭시-나머지-타일-여는-기능-구현하기">8. 주변 타일 중 깃발 타일 개수와 지뢰 타일 개수가 같을 때 숫자타일 클릭시 나머지 타일 여는 기능 구현하기</h2>
<p>숫자타일에 클릭 or 더블클릭 이벤트 설정</p>
<br>
<br>

<h2 id="9-숫자-별로-색-다르게-하기">9. 숫자 별로 색 다르게 하기</h2>
<p>배열 COLOR를 선언하고 타일에 숫자 넣는 과정에서 배열 인덱스로 접근해서 color 다르게 주기
<br>
<br></p>
<h2 id="10-맨-처음-선택하는-타일은-절대-지뢰가-아니다">10. 맨 처음 선택하는 타일은 절대 지뢰가 아니다?</h2>
<p>지뢰찾기 게임에서 제일 처음 선택하는 타일은 절대 지뢰가 나오는 경우가 없다 근데 이걸 어떻게 구현하지???</p>
<br>
<br>

<h2 id="🤔-프로그램-한계--더-생각해-보기">🤔 프로그램 한계 / 더 생각해 보기</h2>
<p>프로그램 멈춤 현상 &gt; 원인
<img src="https://images.velog.io/images/home_2201/post/8f85c289-d869-4ede-ba03-d061ed537831/image.png" alt="">
주변 타일을 click()을 통해 연쇄적으로 실행하는 과정에서 이미 실행되서 열린 타일들을 구분없이 계속해서 click()하면서 call stack이 초과 되었다고 한다. 프로그램이 멈추는 원인을 몰라서 프로젝트를 마무리 하지 못하고 미뤘는데 이렇게 원인을 파악해서 알려주시니 그저 감사할 따름... 누군가 내 깃허브에 방문해서 코드를 봐주는 신선한 경험을 했다</p>
<br>
<br>

<p><a href="https://github.com/1K3H/minesweeper">github - 전체 코드</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTML/CSS] 타일 레이아웃 만들기 flex vs grid]]></title>
            <link>https://velog.io/@home_2201/%ED%83%80%EC%9D%BC-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EB%A7%8C%EB%93%A4%EA%B8%B0-flex-vs-grid</link>
            <guid>https://velog.io/@home_2201/%ED%83%80%EC%9D%BC-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EB%A7%8C%EB%93%A4%EA%B8%B0-flex-vs-grid</guid>
            <pubDate>Tue, 10 Nov 2020 20:19:13 GMT</pubDate>
            <description><![CDATA[<h1 id="📌display-felx">📌DISPLAY: FELX</h1>
<p><a href="https://studiomeal.com/archives/197">1분 코딩 - 이번에야말로 CSS Flex를 익혀보자</a></p>
<pre><code>.parent {
    display: flex;
    flex-direction: row; // 내부요소 가로 정렬
    flex-direction: column; // 내부요소 세로 정렬
    flex-direction: row-reverse; // 내부요소 역순 가로 정렬
    flex-direction: column-reverse; // 내부요소 역순 세로 정렬
 }</code></pre><p>기본적으로 flex 속성은 부모 요소의 display 속성에 flex를 적용하고 내부 요소의 정렬 방향을 정해줘야 한다. 그 이후 내부 요소에 flex 속성을 이용해 부모 요소에서 차지할 비율을 정할 수 있다. 가로로 정렬할지 세로로 정렬할지 선택해야 하기 때문에 <strong>가로 정렬과 세로 정렬을 동시에 할 수는 없다는 한계</strong>가 있다.</p>
<p>그럼에도 불구하고 flex로 타일 레이아웃을 만들어 보겠다고 구현했었다.
<img src="https://images.velog.io/images/home_2201/post/bbec7ffa-9fac-44c7-bb69-4f8da5d6c044/tile%20layout%20html.png" alt="">
<img src="https://images.velog.io/images/home_2201/post/c5562b4b-7489-4030-ae80-febde3c73f34/tile%20layout%20flex%20css.png" alt="">
flex 속성에서 내부 요소는 가로나 세로로 한 줄로 정렬되기 때문에 특정 요소들만 다음 열로 넘기기 위해서 <strong>flex-wrap: wrap;</strong> 속성을 이용했다.</p>
<p>(flex-wrap: wrap; 속성을 설정하기 전 flex box의 default값은 <strong>flex-wrap: nowrap</strong> 인데 이 상태에서는 부모 요소를 벗어나는 요소는 그대로 벗어난 상태로 표현된다.)</p>
<p>flex-wrap: wrap;을 쓰면 부모 요소를 벗어나는 요소는 다음 열로 넘어가게 되는데 이를 이용해서 <strong>윗 열에 위치하게 하고 싶은 요소들의 크기를 조절해 타일 레이아웃을 구현</strong>했다.</p>
<h1 id="📌display-grid">📌DISPLAY: GRID</h1>
<p><a href="https://studiomeal.com/archives/533">1분 코딩 - 이번에야말로 CSS Grid를 익혀보자</a>
flex가 내부 요소의 정렬 방향을 정해야 하는 것에 비해서 grid는 가로, 세로를 동시에 조절할 수 있다.</p>
<p><img src="https://images.velog.io/images/home_2201/post/741dc4ea-8279-429b-9ce2-e1872a30d473/tile%20layout%20html.png" alt="">
<img src="https://images.velog.io/images/home_2201/post/025de865-bde5-49c5-b3d7-d61b934334d7/tile%20layout%20grid%20css.png" alt="">
부모 요소의 display속성에 grid를 설정하고 <strong>grid-template-rows</strong>속성으로 가로 정렬 설정을, <strong>grid-template-columns</strong>속성으로 세로 정렬 설정을 할 수있다.</p>
<h1 id="✍마무리">✍마무리</h1>
<p>flex는 한 방향 정렬, grid는 양 방향 동시 정렬이라는 점에서 언뜻 grid가 flex의 상위에 있는 방식인 것 같기도 하다. 일단 타일 레이아웃 이라는 주제에서는 flex 보다 grid가 더 적절한 방식인 것은 확실한 것 같다. flex와 grid를 많이 사용해 보지 않았기 때문에 flex가 더 적절한 경우가 있는 지는 잘 모르겠지만 일단은 flex와 grid 모두 숙지하고 있어야 할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #9 page layout 변경, 반응형(bootstrap container)]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-9-page-layout-%EB%B3%80%EA%B2%BD-%EB%B0%98%EC%9D%91%ED%98%95bootstrap-container-cytoscape-resize</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-9-page-layout-%EB%B3%80%EA%B2%BD-%EB%B0%98%EC%9D%91%ED%98%95bootstrap-container-cytoscape-resize</guid>
            <pubDate>Tue, 14 Jul 2020 10:16:09 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-디자인-센스가-부족합니다">✔ 디자인 센스가 부족합니다.</h1>
<p>어느 정도 기능 구현은 된 것 같아서 철저하게 기능만을 갖고 있는 페이지를 꾸며 보기로 했다.</p>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;head&gt;
...
  &lt;title&gt;Mind Map Maker&lt;/title&gt;
...
&lt;/head&gt;</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/937f6020-76d8-49e1-815b-b5a5b53a1c80/titlechange.png" alt="">
제일 먼저 계속 Document로 써 있던 title 부분을 바꿨다.</p>
<pre><code class="language-html">...
&lt;head&gt;
...
  &lt;style&gt;
  ...
    h1 {
      padding-bottom: 5px;
      font-size: 45px;
      text-align: center;
      border-bottom: 5px solid black;
    }
  ...
  &lt;/style&gt;
...
&lt;/head&gt;

&lt;body&gt;
...
  &lt;h1&gt;Mind Map Maker&lt;/h1&gt;
...
&lt;/body&gt;</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/5ede16b8-6d19-4d7a-af10-f90e92eeaad8/h1.png" alt="">h1 태그로 제목도 만들어 준다.</p>
<pre><code class="language-html">&lt;head&gt;
...
  &lt;style&gt;
  ...
  input {
    border: 3px solid black;
  }

  .edit_box {
    margin-bottom: 8px;
    text-align: center;
  }

  .form-control {
    width: inherit;
    display: inline;
    border: solid black;
  }

  .btn {
    margin-bottom: 2px;
  }
  ...
  &lt;/style&gt;
...
&lt;/head&gt;

&lt;body&gt;
  &lt;h1&gt;Mind Map Maker&lt;/h1&gt;
  &lt;div class=&quot;edit_box&quot;&gt;
    &lt;input id=&quot;from&quot; type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;FROM&quot;&gt;
    &lt;input id=&quot;to&quot; type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;TO&quot;&gt;
    &lt;button onclick=&quot;save_node()&quot; class=&quot;btn btn-dark&quot; type=&quot;button&quot;&gt;CREATE&lt;/button&gt;
    &lt;button onclick=&quot;delete_node()&quot; class=&quot;btn btn-dark&quot; type=&quot;button&quot;&gt;DELETE&lt;/button&gt;
    &lt;button onclick=&quot;reset()&quot; class=&quot;btn btn-danger&quot; type=&quot;button&quot;&gt;RESET&lt;/button&gt;
  &lt;/div&gt;
&lt;/body&gt;</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/f88d3982-04cb-4340-b385-397d6113eaf8/buttonset.png" alt="">input box들과 button을 edit_box id를 갖는 div로 묶고 bootstrap에 있는 layout을 이용해서 꾸몄다.</p>
<pre><code class="language-html">&lt;head&gt;
...
  &lt;style&gt;
  ...
  #cy {
    border: 5px solid black;
    padding: 0px;
    height: 550px;
    max-width: 95%;
  }
  ...
  &lt;/style&gt;
...
&lt;/head&gt;

&lt;body&gt;
  ...
  &lt;div id=&quot;cy&quot;&gt;&lt;/div&gt;
&lt;/body&gt;</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/939b48ab-3ce2-489b-b6c0-8e35a0c9b3d8/rightblank.png" alt="">cytoscape가 그려지는 부분을 꾸몄는데 (img에서는 잘 구분되지 않지만) 원래 의도(max-width를 95%정도만 줘서 가운데 정렬)와는 다르게 오른쪽만 여백이 생기고 왼쪽에 딱 붙어 있게 나왔다.</p>
<p>저 부분만 또 div로 묶어서 가운데 정렬 해야하나 하던 와중에 bootstrap에서 container라는 걸 발견하고 적용해 봤다.</p>
<pre><code class="language-html">&lt;head&gt;
...
  &lt;style&gt;
  ...
  #cy {
    border: 5px solid black;
    padding: 0px;
    height: 550px;
  }

  .container {
    max-width: 95%;
  }
  ...
  &lt;/style&gt;
...
&lt;/head&gt;

&lt;body&gt;
...
  &lt;div id=&quot;cy&quot; class=&quot;container&quot;&gt;&lt;/div&gt;
&lt;/body&gt;</code></pre>
<p><img src="https://images.velog.io/images/home_2201/post/3c4fe3b4-7d51-4aa6-8699-8ad9a0fee333/bootstrapcontainer.png" alt="">container가 어떻게 작용하는지는 잘 모르겠지만... 원하던 가운데정렬이 잘 된다.</p>
<p><img src="https://images.velog.io/images/home_2201/post/a9288d8d-54da-4318-80a3-786c1d04632a/nodeedgecolorsize.png" alt=""> 마지막으로 node와 edge style을 조정하고 마무리!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #8 DELETE, RESET 구현하기 + alert confirm]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-8-DELETE-RESET-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-alert-confirm</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-8-DELETE-RESET-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-alert-confirm</guid>
            <pubDate>Fri, 10 Jul 2020 12:57:02 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-문제점">✔ 문제점</h1>
<p>input 입력값을 DB에 넣고 빼는 과정을 완성한 시점에서 추가된 node를 삭제하는 기능이 필요하게 됐다.</p>
<p>삭제하는 기능이라고 딱히 다를 건 없고 DB에 data를 넣는 app.py 부분에서 insert 부분만 delete로 바꾸면 될 것 같다.</p>
<h1 id="✔-해결-delete">✔ 해결 DELETE</h1>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;body&gt;
...
  &lt;button onclick=&quot;delete_node()&quot; type=&quot;button&quot;&gt;DELETE&lt;/button&gt;
...
&lt;/body&gt;</code></pre>
<p>우선 button을 하나 더 만들고 클릭 시 실행할 함수를 넣고</p>
<pre><code class="language-html">&lt;script&gt;
...
  // node 지우는 함수
  function delete_node() {
    let from_input = $(&#39;#from&#39;).val();
    let to_input = $(&#39;#to&#39;).val();
    // input 빈칸 검출
    if (from_input == &#39;&#39;) {
      alert(&#39;FROM 값을 입력해 주세요.&#39;);
    } else if (to_input == &#39;&#39;) {
      alert(&#39;TO 값을 입력해 주세요.&#39;);
    } else {
      $.ajax({
        type: &#39;POST&#39;,
        url: &#39;/delete&#39;,
        data: {
          &#39;give_from_input&#39;: from_input,
          &#39;give_to_input&#39;: to_input,
          &#39;give_edge_id&#39;: from_input + to_input
        },
        success: function (response) {
          if (response[&#39;result&#39;] == &#39;success&#39;) {
            window.location.reload();
          }
        }
      });
    }
  };
...
&lt;/script&gt;</code></pre>
<p>ajax (url만 save_node()와 다르게) 작성, delete 함수도 빈칸 검출 포함</p>
<p><strong>app.py</strong></p>
<pre><code class="language-python">@app.route(&#39;/delete&#39;, methods=[&#39;POST&#39;])
def delete_node():
  receive_from_input = request.form[&#39;give_from_input&#39;]
  receive_to_input = request.form[&#39;give_to_input&#39;]
  receive_edge_id = request.form[&#39;give_edge_id&#39;]
  db.nodes.delete_one({
    &#39;from&#39;: receive_from_input,
    &#39;to&#39;: receive_to_input,
    &#39;edge&#39;: receive_edge_id
  })
  return jsonify({&#39;result&#39;:&#39;success&#39;})</code></pre>
<p>app.py에서 route = /delete, delete_one 포함한 식 작성</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/b114d67037760899dea860ebcfb58708f734ef15">GitHub commit</a></p>
<h1 id="✔-문제점-1">✔ 문제점</h1>
<p>delete 기능을 구현 했는데 from과 to input box에 지우려는 id값을 정확하게 입력해서 하나하나 지우는 기능 밖에 하지 못한다. 한꺼번에 다 지우는 reset기능을 구현해야 될 것 같다.</p>
<h1 id="✔-해결-reset">✔ 해결 RESET</h1>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;body&gt;
  ...
  &lt;button onclick=&quot;reset()&quot; type=&quot;button&quot;&gt;RESET&lt;/button&gt;
  ...
&lt;/body&gt;</code></pre>
<p>RESET 버튼 추가하고</p>
<pre><code class="language-html">&lt;script&gt;
  ...
  function reset() {
    $.ajax({
      type: &#39;POST&#39;,
      url: &#39;/reset&#39;,
      success: function (response) {
        if (response[&#39;result&#39;] == &#39;success&#39;) {
          window.location.reload();
        }
      }
    });
  }
...
&lt;/script&gt;</code></pre>
<p>data는 필요 없으니 제외하고 ajax 부분 작성</p>
<p><strong>app.py</strong></p>
<pre><code class="language-python">@app.route(&#39;/reset&#39;, methods=[&#39;POST&#39;])
def reset():
  db.nodes.remove()
  return jsonify({&#39;result&#39;:&#39;success&#39;})</code></pre>
<p>remove() 사용하기</p>
<p>RESET 버튼을 만들고 생각해보니 모든 data가 지워지는 버튼인데 누르면 바로 실행되는건 위험하다는 생각이 들었다. alert을 띄우면 예/아니오 같은 선택지가 나왔으면 좋겠는데 가능한지 모르겠어서 검색!</p>
<p>대충 js alert yes no 라고 검색해보니
<img src="https://images.velog.io/images/home_2201/post/b851df96-25a4-4864-9a72-f578cd357896/confirm.png" alt="">
이런 답변이 나왔다. if 조건문에 confirm을 넣고 &#39;예&#39;를 눌렀을 때 실행될 것은 if 부분에 넣고 &#39;아니오&#39;는 else에 넣으라는 소리인 것 같다.</p>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;script&gt;
...
  function reset() {
    if (confirm(&quot;모든 정보가 삭제됩니다. 진행하시겠습니까?&quot;)) {
      $.ajax({
        type: &#39;POST&#39;,
        url: &#39;/reset&#39;,
        success: function (response) {
          if (response[&#39;result&#39;] == &#39;success&#39;) {
            window.location.reload();
          }
        }
      });
    } else {
      alert(&quot;RESET 취소됨&quot;)
    }
  };
...
&lt;/script&gt;</code></pre>
<p>위처럼 작성하면
<img src="https://images.velog.io/images/home_2201/post/8060dde2-53d5-46ef-beb0-da497cfa466a/comfirmss.png" alt="">이렇게 확인/취소 버튼이 있는 alert이 뜨고 확인을 누르면 모든 data가 다 지워지는 기능이 잘 작동한다. 👏👏👏</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/168064dda9dcd91a87864c6ac4046ebc9c48624a">GitHub commit</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #7 input box 빈칸 검출]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-7-input-box-%EB%B9%88%EC%B9%B8-%EA%B2%80%EC%B6%9C</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-7-input-box-%EB%B9%88%EC%B9%B8-%EA%B2%80%EC%B6%9C</guid>
            <pubDate>Fri, 10 Jul 2020 06:29:20 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-문제점">✔ 문제점</h1>
<p>웹서버에 프로그램을 띄워놓고 버튼이 잘 동작하나 연속해서 눌러보는 도중에 오류가 떴다.
<img src="https://images.velog.io/images/home_2201/post/7e588b78-e897-4add-9cd4-f95534c197ca/blank.png" alt="">
input이 빈칸인 채로 버튼을 누르니 DB에 빈칸이 그대로 저장되었고 id값이 빈칸이니 값을 표현할 수 없다며 오류창을 띄우고 있었다.</p>
<p>다행히 수업 시간에 input box 빈칸 검출하는 법을 배워서 어렵지 않게 해결할 수 있겠다고 생각했다.</p>
<h1 id="✔-해결">✔ 해결</h1>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;body&gt;
  &lt;input id=&quot;from&quot; type=&quot;text&quot; placeholder=&quot;FROM&quot;&gt;
  &lt;input id=&quot;to&quot; type=&quot;text&quot; placeholder=&quot;TO&quot;&gt;
  &lt;button onclick=&quot;save_node()&quot; type=&quot;button&quot;&gt;CREATE&lt;/button&gt;
  &lt;div id=&quot;cy&quot;&gt;&lt;/div&gt;
&lt;/body&gt;</code></pre>
<p>먼저 input box를 구분하기 위해서 placeholder를 입력하고 버튼도 CREATE라고 이름을 바꿔줬다.</p>
<pre><code class="language-html">&lt;script&gt;
  //POST 방식으로 input값을 app.py로 넘김
  function save_node() {
    let from_input = $(&#39;#from&#39;).val();
    let to_input = $(&#39;#to&#39;).val();
    // input 빈칸 검출
    if (from_input == &#39;&#39;) {
      alert(&#39;FROM 값을 입력해 주세요.&#39;);
    } else if (to_input == &#39;&#39;) {
      alert(&#39;TO 값을 입력해 주세요.&#39;);
    } else {
      $.ajax({
        type: &#39;POST&#39;,
        url: &#39;/make&#39;,
        data: {
          &#39;give_from_input&#39;: from_input,
          &#39;give_to_input&#39;: to_input,
          &#39;give_edge_id&#39;: from_input + to_input
        },
        success: function (response) {
          if (response[&#39;result&#39;] == &#39;success&#39;) {
            window.location.reload();
          }
        }
      });
    }
  }
&lt;/script&gt;</code></pre>
<p>if 조건문을 이용해서 input box의 입력값이 빈칸일 경우 빈칸인 input box를 입력하라는 alert을 띄우는 식을 작성하고(if와 else if로 FROM값과 TO값 각각 설정) 빈칸이 아니면 POST방식의 ajax가 실행되도록 설정했다.</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/9f488bba408c3c56965aa161fc4810ab6bea4b6a">GitHub commit</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #6
cytoscape layout 설정]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-5layout-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-5layout-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Fri, 10 Jul 2020 05:03:13 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-문제점">✔ 문제점</h1>
<p><img src="https://images.velog.io/images/home_2201/post/f3453dd3-88fd-448f-ab99-f3506d106e63/cytoscapeposition.png" alt="">
node가 그려질 때 겹쳐서 나오는 문제가 생겼다.</p>
<h1 id="✔-삽질">✔ 삽질</h1>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  ...
  // cytoscape에 elements data를 추가하는 함수
  function initCytoscape(a, b, c) {
    cy.add([
      { group: &#39;nodes&#39;, data: { id: a }, position: { x: 100, y: 100 } },
      { group: &#39;nodes&#39;, data: { id: b }, position: { x: 200, y: 200 } },
      { group: &#39;edges&#39;, data: { id: c, source: a, target: b } }
    ]);
  };
  ...
&lt;/script&gt;</code></pre>
<p>문제가 된다고 예상한 부분은 data를 node로 그려주는 함수에서 position 값이 설정되어 있다는 점인데 &#39;그럼 왜 from 값과 to 값이 각 위치에 겹치지 않고 한 쪽에만 몰려서 겹쳤는가?&#39; 하는 의문이 생겼다. 의문을 풀어보려 id값이 DB에 오가는 과정이나 node가 그려지는 과정을 계속 그려봤지만 결국 해답은 얻지 못하고 실패...</p>
<p>다음으로 생각한 건 &#39;id값을 DB에 넣고 빼는 과정에 위치를 정하는 값을 포함시켜서 node의 위치를 정해줘야 하는가?&#39; 였는데 식을 구상해 보다가 한계를 느끼고 포기...</p>
<p>position 값을 없애면 어떻게 될까?
<img src="https://images.velog.io/images/home_2201/post/3e4f8826-ac57-4e9a-9c8e-badb212d3334/goosuk.png" alt="">
node들이 구석에 박혀 있어서
<img src="https://images.velog.io/images/home_2201/post/160328c3-969a-48e5-a224-22bca798942e/sadfasdf.png" alt="">
마우스로 화면을 끌어와야 보였다 position 값이 없으니 모든 node가 겹쳐서 나오는 건 덤...</p>
<p>어떻게 해결해야 하나 코드를 살피던 중</p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  ...
  const cy = cytoscape({
    ...
    layout: {
      name: &#39;grid&#39;,
      rows: 1
    }
  });
&lt;/script&gt;
...</code></pre>
<p>cytoscape의 본체? 부분에서 layout 값을 발견했는데 layout을 발견하고 든 생각은 맨 처음 (input box를 만들어서 DB에 값을 넣고 빼는 과정을 넣기 전) 에는 이 layout이 있는 부분에 element도 있었고 (지금은 cy.add로 element를 추가해서 안에 sample로 있던 element는 지웠다.) 그 element 안에서 새로운 node를 추가했을 때는 겹쳐서 나오는게 아니라 마인드맵 형태로 잘 그려졌었다는 점이다.</p>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  ...
  const cy = cytoscape({
    ...
    elements: [ // list of graph elements to start with
      { // node a
        data: { id: &#39;a&#39; }
      },
      { // node b
        data: { id: &#39;b&#39; }
      },
      { // node c
        data: { id: &#39;c&#39; }
      },
      { // edge ab
        data: { id: &#39;ab&#39;, source: &#39;a&#39;, target: &#39;b&#39; }
      },
      { // edge bc
        data: { id: &#39;bc&#39;, source: &#39;b&#39;, target: &#39;c&#39; }
      }
    ],
    ...
  });
&lt;/script&gt;</code></pre>
<p>이렇게 추가 했을 때
<img src="https://images.velog.io/images/home_2201/post/bc338ef1-bb0b-46c0-bc90-1640f34216c2/elementincy.png" alt="">
원하는 그림이 나온다.</p>
<p>그럼 문제가 뭘까? cy 안에서 element를 추가하면 layout이 잘 적용되는데 내가 cy.add로 추가한 node들은 layout이 적용이 안된다... 얕은 지식으로 도출해낸 결론은 cy가 그려지고 cy.add가 실행되기 때문에 layout이 add된 node들에는 적용이 안된다는 건데 그럼 어쩌라는 걸까?</p>
<h1 id="✔-해결">✔ 해결</h1>
<p><img src="https://images.velog.io/images/home_2201/post/35bfc812-a499-4630-a974-6d19d68cc5a0/cytolayout.png" alt="">해결방법을 몰라서 하루종일 고민 하던 중 cy.add를 찾았던 것처럼 layout도 뭔가 설정하는 방법이 있지 않을까 하는 생각에 찾아봤더니 나온 방법 (유레카!)</p>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  ...
  // cytoscape에 elements data를 추가하는 함수
  function initCytoscape(a, b, c) {
    cy.add([
      { group: &#39;nodes&#39;, data: { id: a } },
      { group: &#39;nodes&#39;, data: { id: b } },
      { group: &#39;edges&#39;, data: { id: c, source: a, target: b } }
    ]);
    // layout 설정하는 부분
    const layout = cy.layout({
      name: &#39;grid&#39;,
      rows: 1
    });

    layout.run();
  };
...
&lt;/script&gt;</code></pre>
<p>cy.add를 실행하는 함수에 layout을 설정하는 부분도 포함해서 실행되게 고쳤다.
<img src="https://images.velog.io/images/home_2201/post/a6db40d6-b3de-484c-8c30-c9d5dccf5a75/success.png" alt="">드디어 원하던 그림이 그려진다... ㅠ</p>
<pre><code class="language-javascript">const layout = cy.layout({
  name: &#39;cose&#39;
});</code></pre>
<p>layout을 설정하는 부분에서 &#39;grid&#39;라고 되어있던 부분을 &#39;cose&#39;라고 바꾸면 layout을 다른 종류로 바꿀 수도 있다(&#39;grid&#39;와는 다르게 rows는 필요 없어 보이므로 삭제).
<img src="https://images.velog.io/images/home_2201/post/7e10d8d6-0105-4cf7-a39e-e11b9faf9653/layoutcose.png" alt="">&#39;grid&#39;는 좀 딱딱한 느낌이었다면 &#39;cose&#39;는 좀 자유롭게 그려지는 느낌.</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/329b5f41b4582a530d8c5b0bb9aa78ab34050499">GitHub commit</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #5
input box 입력값 DB에 넣고 빼기]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4input-box-%EC%9E%85%EB%A0%A5%EA%B0%92-DB%EC%97%90-%EB%84%A3%EA%B3%A0-%EB%B9%BC%EA%B8%B0</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4input-box-%EC%9E%85%EB%A0%A5%EA%B0%92-DB%EC%97%90-%EB%84%A3%EA%B3%A0-%EB%B9%BC%EA%B8%B0</guid>
            <pubDate>Thu, 09 Jul 2020 04:56:52 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-db에-입력값-넣기">✔ DB에 입력값 넣기</h1>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;body&gt;
  &lt;input id=&quot;test&quot; type=&quot;text&quot;&gt;
  &lt;button onclick=&quot;push()&quot; type=&quot;button&quot;&gt;push&lt;/button&gt;
  &lt;div id=&quot;cy&quot;&gt;&lt;/div&gt;
&lt;/body&gt;</code></pre>
<p>body 태그 안에 input box와 button을 만든다.</p>
<pre><code class="language-html">&lt;script&gt;
  //POST 방식으로 input값을 app.py로 넘김
  function push() {
    let test_input = $(&#39;#test&#39;).val();
    $.ajax({
      type: &#39;POST&#39;,
      url: &#39;/push&#39;,
      data: {
        &#39;give_test_input&#39;:test_input
      },
      success: function (response) {
        if (response[&#39;result&#39;] == &#39;success&#39;) {
          window.location.reload();
        }
      }
    });
  }
&lt;/script&gt;</code></pre>
<p>script 태그를 만들고</p>
<p>(type이 module인 script태그와 따로 만들어야 오류가 안뜸 import한 module이 변수나 식에 포함될 때만 module script에 쓰자)</p>
<p>input 입력값을 id를 통해서 뽑아내고 변수에 저장,
ajax POST 방식으로 변수를 data에 담아 보낸다.</p>
<p>이제 app.py 파일로 넘어가서</p>
<p><strong>app.py</strong></p>
<pre><code class="language-python">@app.route(&#39;/push&#39;)
def push():
  receive_test_input = request.form[&#39;give_test_input&#39;]
  db.inputdata.insert_one({
    &#39;input&#39;:receive_test_input
  })
  return jsonify({&#39;result&#39;:&#39;success&#39;})</code></pre>
<p>ajax로 받은 data를 db에 insert하는 식 입력</p>
<h1 id="✔-db-data를-받아서-cytoscape-element-추가하기">✔ DB data를 받아서 cytoscape element 추가하기</h1>
<p>이제 DB에 data를 넣었으니 저장된 data를 이용해서 cytoscape에 추가해야 되는데 배웠던 내용으로 적용이 안되서 또 한참 삽질을 했다.</p>
<p>배운 내용 : html body태그 내에 div를 만들고 append를 써서 div에 요소들을 추가함</p>
<p>하지만 cytoscape는 화면에 띄워지는 요소들 자체가 html 요소가 아니기 때문에 append로 아무리 시도해 봐도 원하는 결과를 얻을 수 없었다</p>
<p>결국 다시 튜터님께 SOS...
<img src="https://images.velog.io/images/home_2201/post/e273e71c-3b28-46d7-b81c-13e57b1b451b/cytoscapeadd.png" alt="">
cytoscape에서 element를 추가하는 내장함수?가 있다는 사실을 튜터님이 아니었다면 절대 발견하지 못했을 것 같다. (튜터님께 무한한 감사인사를...) </p>
<p>cy.add에 나온 예시에 필요한 값이 3개다 node 2개에 그 둘을 잇는 edge, 그래서 값이 3개가 필요한데 input box를 하나 더 만들어서 node 2개의 값을 주고 edge는 node 2개의 값을 합쳐서 저장하는 방법을 쓰기로 했다.</p>
<p>이제 element를 추가하는 방법은 알았으니 DB에 저장한 data를 불러와서 그려주는 식을 작성해야 된다.</p>
<p><strong>index.html</strong></p>
<pre><code>&lt;body&gt;
  ...
  &lt;input id=&quot;from&quot; type=&quot;text&quot;&gt;
  &lt;input id=&quot;to&quot; type=&quot;text&quot;&gt;
  ...
&lt;/body&gt;</code></pre><p>먼저 input box를 추가하고 id 할당하기!</p>
<p>input box의 id는 edge의 화살표 방향 설정을 위해서 from, to로 정했다.</p>
<p><strong>index.html</strong></p>
<pre><code>&lt;script&gt;
  //POST 방식으로 input값을 app.py로 넘김
  function save_node() {
    let from_input = $(&#39;#from&#39;).val();
    let to_input = $(&#39;#to&#39;).val();
    $.ajax({
      type: &#39;POST&#39;,
      url: &#39;/make&#39;,
      data: {
        &#39;give_from_input&#39;: from_input,
        &#39;give_to_input&#39;: to_input,
        &#39;give_edge_id&#39;: from_input + to_input
      },
      success: function (response) {
        if (response[&#39;result&#39;] == &#39;success&#39;) {
          window.location.reload();
        }
      }
    });
  }
 &lt;/script&gt;</code></pre><p>input box 추가와 edge_id 추가로 인한 함수 수정</p>
<p><strong>app.py</strong></p>
<pre><code class="language-python">@app.route(&#39;/make&#39;, methods=[&#39;POST&#39;])
def save_node():
  receive_from_input = request.form[&#39;give_from_input&#39;]
  receive_to_input = request.form[&#39;give_to_input&#39;]
  receive_edge_id = request.form[&#39;give_edge_id&#39;]
  db.nodes.insert_one({
    &#39;from&#39;: receive_from_input,
    &#39;to&#39;: receive_to_input,
    &#39;edge&#39;: receive_edge_id
  })
  return jsonify({&#39;result&#39;:&#39;success&#39;})</code></pre>
<p>ajax의 data 변화에 따른 app.py 함수 수정</p>
<p><strong>index.html</strong></p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  ...
  // cytoscape에 elements data를 추가하는 함수
  function initCytoscape(a, b, c) {
    cy.add([
      { group: &#39;nodes&#39;, data: { id: a }, position: { x: 100, y: 100 } },
      { group: &#39;nodes&#39;, data: { id: b }, position: { x: 200, y: 200 } },
      { group: &#39;edges&#39;, data: { id: c, source: a, target: b } }
    ]);
  }
&lt;/script&gt;</code></pre>
<p>cy.add 를 포함하는 함수를 선언 (node 와 edge id를 위해 매개변수 설정하기)</p>
<p>이제 ajax를 작성하려고 보니 POST 방식은 ajax 먼저 작성하고 app.py 파일로 넘어갔는데 get은... app.py에서 DB에 요청하는 부분부터 작성해야 될 것 같아서 app.py 부터 작성!</p>
<p><strong>app.py</strong></p>
<pre><code class="language-python">@app.route(&#39;/load&#39;, methods=[&#39;GET&#39;])
def list_node():
  nodes = list(db.nodes.find({}, {&#39;_id&#39;:False}))
  return jsonify({&#39;result&#39;:&#39;success&#39;, &#39;nodes&#39;:nodes})</code></pre>
<p>DB에서 data를 뽑아서 넘기기</p>
<p><strong>index.html</strong></p>
<pre><code>&lt;script type=&quot;module&quot;&gt;
  ...
  function list_node() {
    $.ajax({
      type: &#39;GET&#39;,
      url: &#39;/load&#39;,
      data: {},
      success: function (response) {
        if (response[&#39;result&#39;] == &#39;success&#39;) {
          // db에서 받은 정보 반복문 돌리기
          let node_list = response[&#39;nodes&#39;];
          for (let i = 0; i &lt; node_list.length; i++) {
            let nodes = node_list[i];
            initCytoscape(nodes[&#39;from&#39;], nodes[&#39;to&#39;], nodes[&#39;edge&#39;])
          }
        }
      }
    });
  }
  ...
&lt;/script&gt;</code></pre><p>받은 data를 반복문을 통해서 inintCytoscape 함수에 인자로 넣기</p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  ...
  $(document).ready(function () {
    list_node();
  });
  ...
&lt;/script&gt;</code></pre>
<p>페이지 로딩 완료 시 불러온 data 보여주기 설정</p>
<p><img src="https://images.velog.io/images/home_2201/post/3c0703d2-e195-4471-8841-3532015b40ce/cytoscapeposition.png" alt=""></p>
<p>완성 후 웹 서버에 띄워봤는데 node가 겹쳐서 뜨는 문제가 발생했다.</p>
<p><img src="https://images.velog.io/images/home_2201/post/5b872f9d-ee11-4c69-a204-0d7451ee064d/editposi.png" alt=""></p>
<p>겹쳐진 node를 마우스로 끌어서 옮기면 원하던 결과가 나오는데 이렇게 일일이 node를 옮겨야 한다면 너무 불편하다... 해결 방법을 찾아보자...</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/39d02f877d30c277ae7f07b7422e35c9cdc644a8">GitHub commit</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #4 python으로 로컬서버 연결, mongoDB 연결]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3-python%EC%9C%BC%EB%A1%9C-%EB%A1%9C%EC%BB%AC%EC%84%9C%EB%B2%84-%EC%97%B0%EA%B2%B0-mongoDB-%EC%97%B0%EA%B2%B0</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3-python%EC%9C%BC%EB%A1%9C-%EB%A1%9C%EC%BB%AC%EC%84%9C%EB%B2%84-%EC%97%B0%EA%B2%B0-mongoDB-%EC%97%B0%EA%B2%B0</guid>
            <pubDate>Mon, 06 Jul 2020 07:35:12 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-apppy-파일-만들기-가상환경-만들기">✔ app.py 파일 만들기, 가상환경 만들기</h1>
<pre><code>python -m venv mindmapmakerenv</code></pre><p>가상환경 만들고</p>
<pre><code>pip install flask requests pymongo</code></pre><p>필요한 패키지 설치하고
<img src="https://images.velog.io/images/home_2201/post/333558eb-b9eb-4e33-9319-21cd2c3cbdb2/%ED%8C%8C%EC%9D%BC%EA%B5%AC%EC%A1%B0.png" alt="">
폴더 구조 만들고
<img src="https://images.velog.io/images/home_2201/post/a57f1794-e8dc-4af0-8986-226b6b95aa81/apppy.png" alt="">
로컬 서버, mongoDB 연결!</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/f97ab18f802731f1bbe629df665322691e7b4f93">GitHub commit</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #3 HTML 파일에 모듈을 import 하기]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2-HTML-%ED%8C%8C%EC%9D%BC%EC%97%90-%EB%AA%A8%EB%93%88%EC%9D%84-import-%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2-HTML-%ED%8C%8C%EC%9D%BC%EC%97%90-%EB%AA%A8%EB%93%88%EC%9D%84-import-%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 06 Jul 2020 06:17:34 GMT</pubDate>
            <description><![CDATA[<h1 id="✔-cytoscapejs-cdn-발견">✔ Cytoscape.js CDN 발견</h1>
<p>예제를 따라 만들고 나서 활용할 방법이 없어서 막막하던 상태로 튜터님께 도움을 청했다. 질문을 받으신 튜터님이 Cytoscape.js 페이지를 훑어 보시더니 찾아낸 해결방법
<img src="https://images.velog.io/images/home_2201/post/a4173dee-da08-4041-a2f9-eaa0c910ece4/ssssss.png" alt="">
<img src="https://images.velog.io/images/home_2201/post/bd7d0c2c-c4d3-4b01-aeea-5a729e21e879/cscsc.png" alt=""></p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  import cytoscape from &quot;https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.15.1/cytoscape.esm.min.js&quot;;
&lt;/script&gt;</code></pre>
<p>html 파일 head 부분에 type을 module로 하고 위처럼 import를 해서 html 파일 안에서 모듈을 사용할 수 있었다.</p>
<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
  import cytoscape from &quot;https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.15.1/cytoscape.esm.min.js&quot;;
  var cy = cytoscape({

    container: document.getElementById(&#39;cy&#39;), // container to render in

    elements: [ // list of graph elements to start with
      { // node a
        data: { id: &#39;a&#39; }
      },
      { // node b
        data: { id: &#39;b&#39; }
      },
      { // edge ab
        data: { id: &#39;ab&#39;, source: &#39;a&#39;, target: &#39;b&#39; }
      }
    ],

    style: [ // the stylesheet for the graph
      {
        selector: &#39;node&#39;,
        style: {
          &#39;background-color&#39;: &#39;#666&#39;,
          &#39;label&#39;: &#39;data(id)&#39;
        }
      },
      {
        selector: &#39;edge&#39;,
        style: {
          &#39;width&#39;: 3,
          &#39;line-color&#39;: &#39;#ccc&#39;,
          &#39;target-arrow-color&#39;: &#39;#ccc&#39;,
          &#39;target-arrow-shape&#39;: &#39;triangle&#39;,
          &#39;curve-style&#39;: &#39;bezier&#39;
        }
      }
    ],

    layout: {
      name: &#39;grid&#39;,
      rows: 1
    }

  });
&lt;/script&gt;</code></pre>
<pre><code class="language-html">...

container: document.getElementById(&#39;cy&#39;)

...

&lt;body&gt;
  &lt;div id=&quot;cy&quot;&gt;&lt;/div&gt;
&lt;/body&gt;
</code></pre>
<p>그 후에 basic option 이라고 나와있는 부분을 복붙해 넣고 (type을 module이라고 설정한 script 태그 안에 넣어야 한다 안그러면 오류뜸) id값이 &#39;cy&#39;인 div태그를 body 부분에 추가해 준다음 웹서버에서 실행시키면?</p>
<p>아무것도 안뜬다!? 당황스러워서 개발자 도구를 켜보니 화면에 cy가 있긴 한데 height가 0으로 설정되어 있다.</p>
<pre><code class="language-html">&lt;style&gt;
  #cy {
    height: 550px;
  }
&lt;/style&gt;</code></pre>
<p>style 태그에 적당히 height를 설정하고 다시 ...
<img src="https://images.velog.io/images/home_2201/post/47d76f75-a798-4268-883d-3f0e0ccd7c84/sdfsffffffff.png" alt="">
화면에 원하던 결과가 잘 떴다!</p>
<p><a href="https://github.com/1K3H/MindMapMaker/commit/7854b5151a4c7e91cc604fe62b362df5275b4236">GitHub commit</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #2 예제 따라만들기... 그리고 삽질...]]></title>
            <link>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1-%EC%98%88%EC%A0%9C-%EB%94%B0%EB%9D%BC%EB%A7%8C%EB%93%A4%EA%B8%B0...-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%82%BD%EC%A7%88</link>
            <guid>https://velog.io/@home_2201/Mind-Map-Maker-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1-%EC%98%88%EC%A0%9C-%EB%94%B0%EB%9D%BC%EB%A7%8C%EB%93%A4%EA%B8%B0...-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%82%BD%EC%A7%88</guid>
            <pubDate>Sat, 27 Jun 2020 11:49:27 GMT</pubDate>
            <description><![CDATA[<h1 id="📖-일단--따라서-만들어보자">📖 일단  따라서 만들어보자!</h1>
<p>프로젝트를 시작하기 위해선 Cytoscape.js를 활용해야 한다. 그런데 초보 입장에서 영어+개념 조합은 어디서부터 시작해야 할 지 막막한 끝판왕 보스같은 존재다.</p>
<p>그래서
<a href="https://velog.io/@takeknowledge/%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9-%EB%A7%88%EC%9D%B8%EB%93%9C%EB%A7%B5-cytoscape-%ED%99%9C%EC%9A%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-56k4in7315">velog takeknowledge님 Cytoscape 정리자료</a>
여기서부터 시작하기로 했다.</p>
<p>따라서 만들 수 있도록 정리가 잘 되어있어서 차근차근 만들어 똑같은 결과물을 띄우는데 성공했다.</p>
<h1 id="🤔-삽질의-시작">🤔 삽질의 시작</h1>
<p>결과물을 따라서 만드는 데에는 성공했지만 내가 원하는 기능을 만들기 위해선 프로그램이 작동하는 구조?를 파악할 필요가 있었다. 이해하기 위해서 코드를 계속해서 살펴봤는데 내가 모르는 개념들이 꼬리를 물고 등장해서 이해가 어려웠다... (Node.js, npm, webpack, plugin, loader, babel...?)</p>
<p>이해를 위해선 사용된 개념들의 공부가 우선적이라는 생각에 생활코딩에서 관련된 강의들을 무작정 듣기 시작했다.</p>
<p><a href="https://opentutorials.org/course/3332">생활코딩 Node.js</a>
<a href="https://opentutorials.org/module/4044">생활코딩 npm</a>
<a href="https://opentutorials.org/module/4566/27561">생활코딩 webpack</a></p>
<p>강의 영상 길이를 보고선 금방 끝낼 수 있겠지 싶었지만... 쉽게 이해가 안가서 2주 정도는 계속 강의만 들었다. 문제는 강의를 듣고도 만들어 놓은 예제 파일을 응용해서 내가 원하는 기능을 만들기란 쉽지 않았다.</p>
<p>내가 어렴풋이 구상하고 있던 파일의 구조는 <strong>스파르타 코딩클럽</strong> 수업을 통해 배운 html파일에서 input값을 뽑아서 ajax 방식으로 데이터를 넘기고 app파일을 통해 db와 연결하는 방식이었는데... app파일을 python으로 구현했었고 베이스가 되는 파일이 html이어서 Cytoscape예제와 비교했을 때 어떻게 적용해야 되는지 감이 안잡혔다.</p>
<p>배운 내용과 대충 이해한 예제의 구조를 나란히 써놓고 머리를 싸매다 python으로 구현했던 app파일을 js으로 구현하려면 python에서 사용했던 flask나 pymongo의 기능을 하는 녀석들을 공부해야겠다 싶어서 튜터님께 질문드리니 express와 mongoose라는 녀석을 알게 되었다.</p>
<p>다시 공부...</p>
<p><a href="https://opentutorials.org/course/3370">생활코딩 Node.js-express</a></p>
<p>mongoose는 따로 강의가 없어서 필요한 부분만 검색해서 활용했다.</p>
<p>그렇게 나름대로 공부해서 node.js를 이용해 app파일을 구현하고 로컬서버, mongoDB 연결 등을 했지만 예제 안에서 저렇게 만들어도 무수한 빨간 글씨들만이 나를 반겼다 하하;;; 이것 저것 해본답시고 프로젝트 폴더 전체 삭제만 몇 번짼지...</p>
<p><strong>멘붕이 와서 다른 프로젝트를 시작해야 되나 반쯤 포기상태다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Mind Map Maker] #1 기획안 작성]]></title>
            <link>https://velog.io/@home_2201/%EC%8A%A4%ED%8C%8C%EB%A5%B4%ED%83%80%EC%BD%94%EB%94%A9%ED%81%B4%EB%9F%BD-%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-0-%EA%B8%B0%ED%9A%8D%EC%95%88-%EC%9E%91%EC%84%B1</link>
            <guid>https://velog.io/@home_2201/%EC%8A%A4%ED%8C%8C%EB%A5%B4%ED%83%80%EC%BD%94%EB%94%A9%ED%81%B4%EB%9F%BD-%EA%B0%9C%EC%9D%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-0-%EA%B8%B0%ED%9A%8D%EC%95%88-%EC%9E%91%EC%84%B1</guid>
            <pubDate>Sat, 13 Jun 2020 04:45:32 GMT</pubDate>
            <description><![CDATA[<h1 id="🎈-발단">🎈 발단</h1>
<p>개인적으로 마인드맵을 만드는 프로그램이 필요해 계속해서 찾고 있었다.</p>
<p>아무리 검색해가며 찾아봐도 내가 생각하는 프로그램은 없었고 그나마 맘에 들어서 알아본 프로그램은 대부분 얼마간의 무료 이용 후 결제가 필요한 것들이 대부분 이었다.</p>
<p>그렇게 막연하게 마인드맵 프로그램을 찾고만 있던 와중 &#39;내가 프로그램을 만들 수 있는 방법은 없을까?&#39;하는 생각을 할 때쯤 <strong>&#39;생활코딩&#39;</strong> 사이트에서 강의들의 관계를 보여주는 시각자료로 마인드맵을 사용하고 있는 걸 발견했다. (마인드맵을 만드는 &#39;프로그램&#39;에만 초점을 맞추다 정작 자주 들어가는 사이트에서 찾던 걸 발견했을 때는 드디어 찾았다는 기쁨과 바로 앞에 찾던 걸 놔두고 애먼 곳을 뒤졌다는 허탈감이 동시에 들었다.)</p>
<p>발견한 순간 바로 개발자 도구를 열어서 출처를 알아내려고 했으나
<img src="https://images.velog.io/images/home_2201/post/013c711f-7f25-445e-b512-a47dbf86b464/%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9%20%EB%A7%88%EC%9D%B8%EB%93%9C%EB%A7%B5%20%EC%86%8C%EC%8A%A4.png" alt="">
관련된 소스 중 그나마 출처를 확인할 만한 src에 들어있는 주소로 들어가 봐도 마인드맵만 달랑 있는 페이지만 나올뿐 어떻게 만들어진 건지 알 수 있는 방법이 없었다. (다시 좌절...)</p>
<p>다시 다른 프로그램을 찾아야 되나 고민하던 와중 구글 검색창에 주소에 써져있는 &#39;seomal&#39;이란걸 우연히 검색하게 되었고 그러자 놀랍게도 나처럼 생활코딩에서 저걸 발견하고 글을 쓴 분을 발견했다.</p>
<p><a href="https://velog.io/@takeknowledge/%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9-%EB%A7%88%EC%9D%B8%EB%93%9C%EB%A7%B5-cytoscape-%ED%99%9C%EC%9A%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-56k4in7315">velog takeknowledge님 CYTOSCAPE 정리자료</a></p>
<p>이 글을 통해서 출처가 Cytoscape.js 라는 걸 알게 되었고 그렇게 프로젝트를 시작하게 되었다. </p>
<h1 id="🚩-프로젝트-목적">🚩 프로젝트 목적</h1>
<p>내가 필요로 하는 기능들을 가진 마인드맵 제작 프로그램을 만들자!</p>
<h1 id="📖-기능-요약">📖 기능 요약</h1>
<p>사용자가 값을 입력하면 그 값을 마인드맵으로 표현한다
마인드맵 내부 요소들의 색상, 크기, 요소들 간 연결선 방향, 모양 등을 설정 할 수 있게 한다.
마인드맵 이미지 삽입기능, 마인드맵 편집</p>
<h1 id="🧭-개발해야-하는-부분">🧭 개발해야 하는 부분</h1>
<p>사용자의 입력값을 받아서 마인드맵 형식으로 출력하는 기능 구현 -&gt; input box?
사용자의 설정을 통해 마인드맵의 설정을 바꿀 수 있게 하기 -&gt; tool box?</p>
<h1 id="✍-공부해야-할-것들">✍ 공부해야 할 것들</h1>
<p><a href="https://js.cytoscape.org/">CYTOSCAPE 페이지</a>
<a href="https://velog.io/@takeknowledge/%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9-%EB%A7%88%EC%9D%B8%EB%93%9C%EB%A7%B5-cytoscape-%ED%99%9C%EC%9A%A9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-56k4in7315">velog takeknowledge님 CYTOSCAPE 정리자료</a></p>
]]></description>
        </item>
    </channel>
</rss>