React 리액트 기초부터 쇼핑몰 프로젝트까지!

react 공부를 하고싶어서 유료 강의를 사서 보았다.

코딩애플 아저씨 예전부터 유튜브로도 보고 ES6 유료 강의도 봤었는데.. 후기를 리스트 형식으로 간단하게 적어보려고 한다!!

 

 

  1. 설명 이해가 쏙쏙되게 말을 찰지게 하심
  2. 응용이 되게 원리를 설명해주실 때가 많음 → 하지만 막 엄청 깊숙히 설명 해주시지는 않고 딱 간결하게? 오히려 이게 더 좋은거 같기도 하다.
  3. 왜 써야하는지 이유를 설명해주시니 2번과 같이 응용할 때 많은 도움이 된다.
  4. 중요한 것들은 계속 자막으로 반복해서 띄워주셔서 머릿속에 강제로 주입시켜야하는 느낌 (이런것들은 진짜 외워야 원할히 진행가능 할 때 많음..)
  5. 과제를 내줘서 혼자 정리하고 생각할 시간을 주심 → 정답도 있어서 코드 비교 가능★
  6. 5번과 비슷한데 과제를 내주는데 정답에 뭔가 빡치는 문장 써놔서 정답 안보고 풀게 해놓으심..

써놓고 보니 대부분 장점인데.. 그만큼 괜찮은 강의였다.  부가 설명을 하자면

1번 장점은 인상깊은 설명이 props를 설명해주실 때 불륜, 패륜이다.

1번 장점

 

6번 장점은 예를 들면 아래와 같은것들..

6번 장점(?)

누군가에게는 기분이 나쁠수도 있지만 저는 오히려 좋아♥

 

물론 6번은 평소에는 동기부여가 되는 문장을 써주신다.

평상시 정답 문구1
평상시 정답 문구2

 

 

이상입니다아아

1. [4장 실습용 문제] (4-1에서 이어지는 문제)

/******************************************************************************
 * 문제 4-2
 ******************************************************************************/
// 새로운 프로젝트와 Main.java 소스파일을 만든 후 [문제 4-1]에서 작성한 소스코드를 복사해서 삽입하라.
// [문제 4-2] 실행 결과를 참고하여 아래 코드를 작성하라.
// 1) 기존의 main() 함수 내에 있던 String[] name, int[] tall 변수를 Manager 클래스의 
//    static private 멤버로 옮겨라.
// 2) 아래 main() 함수에서 호출하는 Manager.makeManager(in) 문장을 참조하여 Manager 클래스에 
//    해당 함수를 구현하라. 기존 [문제 4-1]의 main 함수에 있던 manager 객체 
//    생성하는 코드들(while 문장 앞까지의 코드)를 makeManager(in) 함수로 옮기면 된다.
//    그리고 생성된 manager 객체를 리턴하면 된다.
// 3) Manager 객체는 항상 makeManager(in) 함수를 사용하여 생성하고 사용자가 직접 
//    new Manager(3) 형태로 호출하여 객체를 생성할 수 없게 하라.
// 4) 기존 main() 함수를 아래 main() 함수로 교체하라.
// 5) 메뉴 항목 "4.FindStudent2"를 선택할 경우 manager.findStudent(pname, tall)가 호출된다.
//    이 함수를 구현하라. 이 함수는 Manager가 관리하는 학생 중에 입력된 이름과 키가 
//    각각 pname과 tall과 동일한 학생을 찾아 출력한다. 찾지 못한 경우 적절한 에러 메시지를 출력한다.

 

public class Main
{
    public static void main(String[] args) 
    {
        Scanner in = new Scanner(System.in);
        Manager manager = Manager.makeManager(in);
        // manager = new Manager(3); 
        // 위 문장의 주석을 제거하면 Manager 생성자 접근할 수 없다는 에러가 발생하여야 한다.

        while(true) {
            System.out.print("\n0.Exit 1.DisplayAll 2.CalculateMean\n");
            System.out.print("3.FindStudent 4.FindStudent2 5.MakeManager >> ");
            int input = in.nextInt();
            if (input == 0)
            	break;
            switch (input) {
            case 1: manager.displayAll();       
                    break;
            case 2: manager.calculateMean();    
                    break;
            case 3: System.out.print("name? ");
                    String pname = in.next();
                    manager.findStudent(pname);
                    break;
            case 4: System.out.print("name, tall? ");
                    pname = in.next();
                    int tall = in.nextInt();
                    manager.findStudent(pname, tall);
                    break;
            case 5: manager = Manager.makeManager(in);
                    break;
            }
        }
        in.close();
    }
}

실행결과 예시

===============================================================================
==  [문제 4-2] 실행 결과
=============================================================================== 
input continuously 6 indices(index) of array: 0 1 2 3 4 5 // 사용자 입력: 0 ~ 5 숫자를 임의의 순서로 입력

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 1
name	tall	difference
bob	172	  0.00
john	183	  0.00
alice	168	  0.00
nana	161	  0.00
tom	171	  0.00
sandy	172	  0.00

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 2
tall mean: 171.17

name	tall	difference
bob	172	  0.83
john	183	 11.83
alice	168	 -3.17
nana	161	-10.17
tom	171	 -0.17
sandy	172	  0.83

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 5
input continuously 6 indices(index) of array: 5 4 3 2 1 0 // 사용자 입력: 0 ~ 5 숫자를 임의의 순서로 입력

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 1 // 새로운 manager 객체가 생성되었고, 배열에 들어간 객체 순서도 다름 
name	tall	difference
sandy	172	  0.00
tom	171	  0.00
nana	161	  0.00
alice	168	  0.00
john	183	  0.00
bob	172	  0.00

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 2
tall mean: 171.17

name	tall	difference
sandy	172	  0.83
tom	171	 -0.17
nana	161	-10.17
alice	168	 -3.17
john	183	 11.83
bob	172	  0.83

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 4
name, tall? nana 161
nana	161	-10.17

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 4
name, tall? nana 160
nana 160: not found.

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 4
name, tall? NANA 161
NANA 161: not found.

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 4
name, tall? bob 171
bob 171: not found.

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 4
name, tall? bob 172
bob	172	  0.83

0.Exit 1.DisplayAll 2.CalculateMean
3.FindStudent 4.FindStudent2 5.MakeManager >> 0

 

2. 정답코드

import java.util.Scanner;

class Student { 
    // 아래 name, tall, diff는 반드시 private로 하라.
    private String name;
    private int tall;
    private double diff;

    public Student(String name, int tall){
      this.name = name;
      this.tall = tall;
    }
  
    public void printStudent() {
       System.out.printf("%s\t%d\t%6.2f\n", name, tall, diff);
    }
    // 필요한 경우 멤버 값을 설정하고 구해오는 메소드(함수)를 만들어 멤버에 접근하라.
    public int getTall(){
      return this.tall;
    }

    public void setDiff(double diff){
      this.diff = diff;
    }
    public String getName(){
      return this.name;
    }
}

// 필요한 메소드(함수)를 구현하라.
class Manager {
  private static String[] name = {"bob", "john", "alice", "nana", "tom", "sandy"};
  private static int[] tall = {172, 183, 168, 161, 171, 172};
  private int curIndex;
  private Student[] students;
  
  private Manager() {}
  
  private Manager(int length){
    this.curIndex = 0;
    students = new Student[length];
  }
  
  public static Manager makeManager(Scanner in) {
     Manager manager = new Manager(Manager.name.length);
     System.out.print("input continuously 6 indices(index) of array: ");
      
      // 0 ~ 5 사이의 서로 다른 6개의 숫자(임의의 순서)들을 연속적으로 입력 받으면서
      // 학생 객체를 생성한 후 manager에 등록한다.
      for(int i = 0; i < Manager.name.length; i++)  {
          int j = in.nextInt();
          // manager 객체의 append 메소드를 실행하여 학생 객체 등록
          // append()는 manager내의 학생 객체 배열에 순서적으로 삽입한다.
          manager.append(new Student(name[j], tall[j]));
      }
      return manager;
  }

  public void displayAll(){
    System.out.printf("name\ttall\tdifference\n");
    for(int i=0; i<students.length; i++){
      this.students[i].printStudent();
    }
  }

  public void calculateMean(){
    double total = 0;
    for(int i=0; i<students.length; i++){ //total 구하기
      total += this.students[i].getTall();
    }
    total /= this.students.length;
    for(int i=0; i<students.length; i++){ //diff 구하기
      this.students[i].setDiff(this.students[i].getTall() - total);
    }
    
    System.out.printf("tall mean:%.2f\n\n",total);
    
    this.displayAll();
  }

  public void append(Student s){
    students[curIndex++] = s;
  }

  public void findStudent(String name){
    boolean findFlag = true;
    for(int i=0; i<students.length; i++){
      if(students[i].getName().equals(name)){
        findFlag = false;
        students[i].printStudent();
      }
    }
    if(findFlag){
      System.out.println(name+": not found.");
    }
  }
  
  public void findStudent(String name, int tall) {
     boolean findFlag = true;
       for(int i=0; i<students.length; i++){
         if(students[i].getName().equals(name) && students[i].getTall()==tall){
           findFlag = false;
           students[i].printStudent();
         }
       }
       if(findFlag){
         System.out.println(name+": not found.");
       }
  }
  
  
}

public class Main {

    public static void main(String[] args) 
    {
       Scanner in = new Scanner(System.in);
        Manager manager = Manager.makeManager(in);
        // manager = new Manager(3); 
        // 위 문장의 주석을 제거하면 Manager 생성자 접근할 수 없다는 에러가 발생하여야 한다.

        while(true) {
            System.out.print("\n0.Exit 1.DisplayAll 2.CalculateMean\n");
            System.out.print("3.FindStudent 4.FindStudent2 5.MakeManager >> ");
            int input = in.nextInt();
            if (input == 0)
               break;
            switch (input) {
            case 1: manager.displayAll();       
                    break;
            case 2: manager.calculateMean();    
                    break;
            case 3: System.out.print("name? ");
                    String pname = in.next();
                    manager.findStudent(pname);
                    break;
            case 4: System.out.print("name, tall? ");
                    pname = in.next();
                    int tall = in.nextInt();
                    manager.findStudent(pname, tall);
                    break;
            case 5: manager = Manager.makeManager(in);
                    break;
            }
        }
        in.close();

    }
}

 

3. 대충 풀이

1) 기존의 main() 함수 내에 있던 String[] name, int[] tall 변수를 Manager 클래스의 static private 멤버로 옮겨라. 

이건 너무 쉬우니까 패스...

2) 아래 main() 함수에서 호출하는 Manager.makeManager(in) 문장을 참조하여 Manager 클래스에 해당 함수를 구현하라. 기존 [문제 4-1]의 main 함수에 있던 manager 객체 생성하는 코드들(while 문장 앞까지의 코드)를 makeManager(in) 함수로 옮기면 된다. 그리고 생성된 manager 객체를 리턴하면 된다.

public static Manager makeManager(Scanner in) {
     Manager manager = new Manager(Manager.name.length);
     System.out.print("input continuously 6 indices(index) of array: ");
      
      // 0 ~ 5 사이의 서로 다른 6개의 숫자(임의의 순서)들을 연속적으로 입력 받으면서
      // 학생 객체를 생성한 후 manager에 등록한다.
      for(int i = 0; i < Manager.name.length; i++)  {
          int j = in.nextInt();
          // manager 객체의 append 메소드를 실행하여 학생 객체 등록
          // append()는 manager내의 학생 객체 배열에 순서적으로 삽입한다.
          manager.append(new Student(name[j], tall[j]));
      }
      return manager;
  }

2번 풀이

Manager.makeManager로 호출하였으므로 해당 메소드는 static 이어야하므로 static으로 선언해준다.

①  Manager 객체를 생성한다.

② 생성된 Manager 객체에 append 메소드를 통해 학생 정보를 넣어서 학생객체 배열을 관리할 수 있도록 해준다.

③ 설정이 끝난 Manager 객체를 반환해준다.

 

 

3) Manager 객체는 항상 makeManager(in) 함수를 사용하여 생성하고 사용자가 직접 new Manager(3) 형태로 호출하여 객체를 생성할 수 없게 하라.

3번 풀이

① 사용자가 직접 new 키워드를 사용하여 객체를 생성하지 못하도록 생성자를 private로 선언해준다.

 

4) 기존 main() 함수를 아래 main() 함수로 교체하라. (너무 쉬우니 패스)

5) 메뉴 항목 "4.FindStudent2"를 선택할 경우 manager.findStudent(pname, tall)가 호출된다.이 함수를 구현하라. 이 함수는 Manager가 관리하는 학생 중에 입력된 이름과 키가 각각 pname과 tall과 동일한 학생을 찾아 출력한다. 찾지 못한 경우 적절한 에러 메시지를 출력한다.

5번 풀이

기본적으로 기존 findStudent 메소드와 같다.

① 기존의 findStudent이다. 

② 새로 생성된 findStudent이다. Main 메소드를 보면 3번 또는 4번 모두 manager.findStudent를 호출하고 있다. 이는 바로 메소드 오버로딩을 이용하라는 의미이다. (같은 메소드 이름이지만 메소드 시그니처를 다르게 하여 서로 구분하는 것) 매개변수 갯수를 다르게 하여 메소드 오버라이딩을 구현하였다.

③ 새로 생성된 findStudent 로직 중 기존과 다른 점은 그저 키까지 같이 비교하는 부분이다. AND(&&) 조건을 이용하여 구현하면 끝~

'코딩이야기 > 연습문제' 카테고리의 다른 글

[라이브코딩 연습] JAVA 실습문제 4-1  (0) 2022.11.01
JAVA 실습문제 3-2  (0) 2022.10.28
JAVA 실습문제 3-1  (0) 2022.10.28
JAVA 실습문제 3-3  (0) 2022.10.25

1. 문제

/******************************************************************************
 * 문제 4-1
 ******************************************************************************/
// 새로운 프로젝트를 만든 후 새로운 클래스 Main를 만들어 Main.java 소스파일을 만들어라.
// 그런 후 아래 main 메소드를 복사해 소스파일에 넣어라.

 

// 클래스 정의, 생성자, 접근자, 객체배열 및 정적클래스와 관련된 문제이다.
// 아래 프로그램은 Student, Manager, Main으로 구성된다.
//
// 프로그램의 실행결과를 먼저 확인하라.
// 먼저 0 ~ 5 사이의 서로 다른 6개의 숫자를 임의의 순서로 연속적으로 입력 받는다.
// 이는 Manager에 추가할 학생들의 인덱스 순서이다.
// 그런 후 5명의 학생 객체를 생성하여 Manager에 추가한다.
// Manager는 5명의 학생 객체를 객체 배열에 저장하여 관리한다.
//
// Student, Manager 클래스의 멤버는 필요에 따라 추가해야 한다.
//
// 메뉴의 각 항목의 기능은 다음과 같으며, 이 순서로 구현하라.
// 1.DisplayAll: Manager가 관리하는 모든 학생 정보를 출력해야 한다.
//   Student의 printStudent()를 활용하라. 오타를 줄이기 위해 아래 문장도 사용하라.
       //System.out.printf("name\ttall\tdifference\n");
//
// 2.CalculateMean: Manager가 관리하는 모든 학생들의 키의 평균 값을 구해서 출력하고
//   이때 오타를 줄이기 위해 아래 문장을 사용하라.
        //System.out.printf("tall mean: %.2f\n\n", mean);
//   각 학생의 키와 평균과의 차이 값을 각 학생 객체의 diff 멤버에 저장하라. (키가 평균보다 작으면 음수 값이 된다.)
//   그리고 학생 전체를 다시 디스플레이하라.
//
// 3.FindStudent: Manager가 관리하는 학생 중에 입력된 이름과 동일한 이름을 가진 학생을 찾아 출력한다.
//                찾지 못한 경우 아래의 에러 메시지를 출력한다.
       //System.out.println(name+": not found.");
//
//=============================================================================

 

2. 전체코드

class Student { 
    // 아래 name, tall, diff는 반드시 private로 하라.
    private String name;
    private int tall;
    private double diff;

    public Student(String name, int tall){
      this.name = name;
      this.tall = tall;
    }
  
    public void printStudent() {
       System.out.printf("%s\t%d\t%6.2f\n", name, tall, diff);
    }
    // 필요한 경우 멤버 값을 설정하고 구해오는 메소드(함수)를 만들어 멤버에 접근하라.
    public int getTall(){
      return this.tall;
    }

    public void setDiff(double diff){
      this.diff = diff;
    }
    public String getName(){
      return this.name;
    }
}

// 필요한 메소드(함수)를 구현하라.
class Manager {
  private int curIndex;
  private Student[] students;
  
  public Manager(int length){
    this.curIndex = 0;
    students = new Student[length];
  }

  public void displayAll(){
    System.out.printf("name\ttall\tdifference\n");
    for(int i=0; i<students.length; i++){
      this.students[i].printStudent();
    }
  }

  public void calculateMean(){
    double total = 0;
    for(int i=0; i<students.length; i++){ //total 구하기
      total += this.students[i].getTall();
    }
    total /= this.students.length;
    for(int i=0; i<students.length; i++){ //diff 구하기
      this.students[i].setDiff(this.students[i].getTall() - total);
    }
    
    System.out.printf("tall mean:%.2f\n\n",total);
    
    this.displayAll();
  }

  public void append(Student s){
    students[curIndex++] = s;
  }

  public void findStudent(String name){
    boolean findFlag = true;
    for(int i=0; i<students.length; i++){
      if(students[i].getName().equals(name)){
        findFlag = false;
        students[i].printStudent();
      }
    }
    if(findFlag){
      System.out.println(name+": not found.");
    }
  }
}

public class Main {

    public static void main(String[] args) 
    {
        Scanner in = new Scanner(System.in);
        String[] name = {"bob", "john", "alice", "nana", "tom", "sandy"};
        int[] tall = {172, 183, 168, 161, 171, 172};

        // Manager 클래스의 객체변수 manager 선언 및 객체 생성
        // name.length는 manager내에 생성될 학생배열의 길이임
        Manager manager = new Manager(name.length);

        System.out.print("input continuously 6 indices(index) of array: ");
        
        // 0 ~ 5 사이의 서로 다른 6개의 숫자(임의의 순서)들을 연속적으로 입력 받으면서
        // 학생 객체를 생성한 후 manager에 등록한다.
        for(int i = 0; i < name.length; i++)  {
            int j = in.nextInt();
            // manager 객체의 append 메소드를 실행하여 학생 객체 등록
            // append()는 manager내의 학생 객체 배열에 순서적으로 삽입한다.
            manager.append(new Student(name[j], tall[j]));
        }

        while(true) {
            System.out.print("\n0.Exit 1.DisplayAll 2.CalculateMean 3.FindStudent >> ");
            int input = in.nextInt();
            if (input == 0)
               break;
            switch (input) {
            case 1: manager.displayAll();       
                    break;
            case 2: manager.calculateMean();    
                    break;
            case 3: System.out.print("name? ");
                    String pname = in.next();
                    manager.findStudent(pname);
                    break;
            }
        }
        in.close();
    }
}

 

객체 배열을 사용하는것이 포인트!

'코딩이야기 > 연습문제' 카테고리의 다른 글

[라이브코딩 연습] JAVA 실습문제 4-2  (0) 2022.11.01
JAVA 실습문제 3-2  (0) 2022.10.28
JAVA 실습문제 3-1  (0) 2022.10.28
JAVA 실습문제 3-3  (0) 2022.10.25

고정 레이아웃과 canvas에 이미지 불러오는 부분은 따로 정리해두었으니 참고!!

 

이 예제에는 드래그모드와 클릭모드 총 2가지 모드와 지우개가 구현되어있다.

드래그모드는 마우스 누름 → 드래그 → 마우스 놓음 순서로 이벤트를 잡아서 누른순간부터 놓는 순간의 영역만큼 모자이크를 하는 것이고, 클릭 모드는 미리 정해진 영역에 클릭을 하면 그 영역만 모자이크가 되는 원리이다.

 

예제 설명은 드래그모드 위주로!! (드래그 모드가 더 어려웠음.. ㅠㅠ)

 

공통사항

1. 캔버스는 모두 3개가 필요하다.

  • 원본이 그려질 캔버스(originCanvas)
  • 모자이크가 되어질 캔버스(mozaicCanvas)
  • 마우스의 움직임(드래그, 호버)에 따라 사각형을 그려줄 캔버스(hoverCanvas)

2. 지우개와 모자이크가 되는 방식은 모두 동일하다. (모자이크 되는 영역이 다를뿐이다.)

3. 이미지 불러오기와 고정 레이아웃은 다른 게시글에 설명이 있다.

 

드래그 모드의 핵심

드래그모드의 이벤트 순서

  1. 마우스 누름 (mousedown) → 시작좌표 획득
  2. 드래그 (mousemove)   → hover영역에 영역을 알려주는 빨간색 네모상자를 그려주는 역할
  3. 마우스 놓음 (mouseup) → 끝좌표 획득 및 width와 height를 구하여 모자이크 실행

좌표 확득
width, heigth 구하기 (초록색, 파란색)

래스터 정보와 getImageData

이미지는 수많은 픽셀로 구성되어 있다. 이미지를 구성하는 픽셀 정보를 래스터(Raster)라고 하며 이미지 표면에 어떤 그림이 그려져 있는지를 저장한다. 래스터 데이터를 직접 조작하면 그리기 메서드로는 불가능한 효과를 낼 수 있다.

 

좌표와 width,height를 구하는 이유는 래스터 정보를 얻을 수 있는 getImageData(x, y, w, h) 메소드의 파라미터이기 때문이다.

전체코드

[HTML 코드 + CSS코드]

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>테스트</title>
    <link rel="stylesheet" href="reset.css">
    <style>
        html,body{
            height: 100%;
        }
        .wrap{
            min-width: 800px; /*전체 사이트의 길이가 800px보다 작아지지 않도록 설정*/
            height: 100%;
        }
        .header{
            height: 100px;
            position: fixed;
            top: 0; left: 0; right: 0;
            background-color: aqua;
            z-index: 100;
        }
        .container{
            /* height를 %로 지정하기 위해서는 부모요소로 부터 높이값을 상속받아야한다. */
            min-height: 100%;
            margin: 0 auto;
            margin-top: -100px;
            padding-top: 200px;  /* padding으로 해야 border-box를 사용하여 원하는 레이아웃을 만들 수 있다. */
            box-sizing: border-box;
        }
        .content{
            margin: 0 auto;
            max-width: 1200px;
            background-color: aliceblue;
        }
        .footer{
            width: 100%;
            min-height: 100px;
            background-color: blue;
        }
        #canvas_area{
            position: relative;
            display: inline-block;
            width: 100%;
            height: 600px;
            overflow: auto;
        }
        #canvas_area canvas{
            position: absolute;
            left: 0;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="header">
            <div>
                <button id="mode_change">모드변경</button>
                <button id="eraser">지우개</button>
            </div>
            <div>
                <input type="file" id="img_loading"></button>
            </div>
            
        </div>
        <div class="container">
            <div class="content">
                <div id="canvas_area">
                    <canvas id="origin"></canvas> <!--원본-->
                    <canvas id="mosaic"></canvas> <!--모자이크 영역-->
                    <canvas id="hover"></canvas> <!--마우스영역-->
                </div>
            </div>
        </div>
        <div class="footer">footer</div>
    </div>
</body>
<script>
...
</script>
</html>

[JS코드]

<script>
    class Mozaic{

        constructor(){
            window.mode = 0; //드래그 모드

            this.$originCanvas = document.querySelector("#origin");
            this.$mosaiCanvasc = document.querySelector("#mosaic");
            this.$hoverCanvas = document.querySelector("#hover");

            this.$imgLoading = document.querySelector("#img_loading");
            this.$eraser = document.querySelector("#eraser");
            this.$modeChange = document.querySelector("#mode_change");
            
            this.originCtx = this.$originCanvas.getContext('2d');
            this.mosaicCtx = this.$mosaiCanvasc.getContext('2d');
            this.hoverCtx = this.$hoverCanvas.getContext('2d');
            
            this.eventBinding();
            this.init();
        }

        //초기화
        init(mode=0){
            window.isErase = false;
            window.isDrag = false;
            window.sx=0, window.ex=0;
            window.sy=0, window.ey=0;
            this.hoverCtx.clearRect(0,0,this.$hoverCanvas.width, this.$hoverCanvas.height); //그려진 호버 영역 지우기
            if(mode===1){ //클릭모드 초기화 
                //모자이크 영역 초기화
                window.mozXSize = 15;
                window.mozYSize = 15;
            }
        }

        eventBinding(){
            this.$imgLoading.addEventListener('change',this.loadImg.bind(this));
            //드래그 ↔ 클릭 모드 변경
            this.$modeChange.addEventListener('click',()=>{
                window.mode = Number(!window.mode); //모드 체인지 (0:드래그[기본], 1:클릭)
                this.isErase = false; //지우개 선택되었을 시 지우개 해제
                this.init(window.mode);
                console.log('현재 모드 : ', window.mode);
            });
            //지우개 클릭 : 지우개 모드 활성화
            this.$eraser.addEventListener('click',()=>{
                window.isErase = true;
            });
            
            this.$hoverCanvas.addEventListener('mousedown',(e)=>this.hoverCanvasMouseDown.call(this,e));
            this.$hoverCanvas.addEventListener('mousemove',(e)=>this.hoverCanvasMouseMove.call(this,e));
            this.$hoverCanvas.addEventListener('mouseup',(e)=>this.hoverCanvasMouseUp.call(this,e));
            this.$hoverCanvas.addEventListener('mouseout',(e)=>this.hoverCanvasMouseOut.call(this,e));
            this.$hoverCanvas.addEventListener('click',(e)=>this.hoverCanvasMouseClick.call(this,e));
        }
        
        //호버영역 마우스 벗어났을 때 핸들링
        hoverCanvasMouseOut(e){

        }

        //호버영역 마우스 드래그 시작 (드래그 모드)
        hoverCanvasMouseDown(e){
            if(window.mode===0){ //드래그 모드인지 확인
                window.isDrag = true;
                window.sx = e.layerX;
                window.sy = e.layerY;
                this.hoverCtx.strokeRect(sx,sy,0,0);
            }
        }
        
        //호버영역 마우스 클릭(클릭모드)
        hoverCanvasMouseClick(e){
            if(window.mode === 1){
                //좌표가져오기
                window.ex = Math.max(0, e.layerX);
                window.ey = Math.max(0, e.layerY);
                const imgData = this.originCtx.getImageData(window.ex,window.ey,window.mozXSize,window.mozYSize);
                this.doMosaic(imgData,ex,ey);
            }
        }

        //호버영역 마우스 드래그 끝 (드래그 모드)
        hoverCanvasMouseUp(e){
            if(window.mode === 0){ //드래그 모드 
                isDrag = false; //드래그끝을 알린다.
                this.hoverCtx.clearRect(0,0,this.$hoverCanvas.width, this.$hoverCanvas.height); //표시된 드래그 영역 삭제

                window.ex = e.layerX;
                window.ey = e.layerY;

                const startX = Math.min(window.sx, window.ex);
                const startY = Math.min(window.sy, window.ey);
                const endX = Math.max(window.sx,window.ex);
                const endY = Math.max(window.sy,window.ey);

                const imgData = this.originCtx.getImageData(startX,startY, endX - startX, endY - startY);
                this.doMosaic(imgData,startX,startY);
            }
        }

        //호버영역 마우스 이동 (드래그모드, 클릭 모드)
        hoverCanvasMouseMove(e){
            if(window.mode === 0){ //드래그 모드 확인
                if(isDrag){ //드래그 중일때만 동작
                    this.hoverCtx.clearRect(0,0,e.target.width, e.target.height);
                    this.hoverCtx.strokeStyle = "#FF0000"; //빨간색으로 드래그 영역 잡히게 설정
                    this.hoverCtx.strokeRect(sx,sy, e.layerX - sx, e.layerY - sy);
                }
            }else if(window.mode === 1){ //클릭 모드
                //좌표 가져오기
                const x = Math.max(e.layerX,0);
                const y = Math.max(e.layerY,0);
                //기존 호버영역 그려진 것들 삭제
                this.hoverCtx.clearRect(0,0,e.target.width, e.target.height);
                this.hoverCtx.strokeStyle = 'black';
                this.hoverCtx.strokeWidth = 30;
                this.hoverCtx.fillStyle = 'rgba(0,255,255,0.5)';
                this.hoverCtx.fillRect(x,y,window.mozXSize, window.mozYSize);
            }
        }

        //이미지 불러오기
        loadImg(){
            const file = this.$imgLoading.files[0];
            console.log(file);
            if(!file.type.match(/image.*/)){
                alert('이미지 파일이 아닙니다.');
                return;
            }
            
            const reader = new FileReader();
            reader.onload = (e)=>{
                const img = new Image();
                img.onload = ()=>{
                    this.$originCanvas.width = img.width;
                    this.$originCanvas.height = img.height;
                    
                    this.$mosaiCanvasc.width = img.width;
                    this.$mosaiCanvasc.height = img.height;

                    this.$hoverCanvas.width = img.width;
                    this.$hoverCanvas.height = img.height;

                    this.originCtx.drawImage(img,1,1);
                    this.mosaicCtx.drawImage(img,1,1);
                }
                img.src = e.target.result;
            }
            reader.readAsDataURL(file);
        }

    }
    new Mozaic();
</script>

reset.css
0.00MB

reset.css를 다운로드 받아서 같은 경로에 놔두면 된다.

 

[결과물]

drag 모드

 

클릭모드

 

참고사이트

http://www.soen.kr/html5/html3/3-2-2.htm

 

HTML5 매뉴얼

3-2-2.이미지 데이터 이미지는 수많은 픽셀로 구성되어 있다. 이미지를 구성하는 픽셀 정보를 래스터(Raster)라고 하며 이미지 표면에 어떤 그림이 그려져 있는지를 저장한다. 래스터 데이터를 직

www.soen.kr

 

1. 문제

/******************************************************************************
 * 문제 3-2
 ******************************************************************************/
// 새로운 프로젝트와 Main.java 소스파일을 만든 후 [문제 3-1]에서 작성한 소스코드를 복사해서 삽입하라.
// [문제 3-2] 실행 결과를 참고하여 아래 코드를 완성하라.

 

public class Main
{
    public static int[][] makeArray(Scanner s) {
        기존 함수를 다음과 같이 수정하라.
        출력 결과를 참고하여 비정방형 배열 arr[][]을 생성한 후 
        해당 배열의 각 원소를 출력 결과처럼 초기화한 후 배열을 리턴한다.
    }

    public static void printArray(int arr[][]) {
        기존 코드와 동일
    }
    
    public static void main(String[] args) {
        기존 코드와 동일함
    }
}

 

해당 문제는 1번 문제에서 만들었던 정방형 배열을 비정방형으로 바꾸는 꽤나 쉬운 문제였다.

 

2. 전체코드

import java.util.*;

class Main {
   public static int[][] makeArray(Scanner s) {
      System.out.print("array size? ");
      int length = s.nextInt();
      int arr[][] = new int[length][];
      for(int i=0; i<length; i++){
        arr[i] = new int[length - i]; //비정방형 배열 생성
        int colLength = arr[i].length;
        int value = i; //행마다 시작값이 바뀌게 설정.
        for(int j=0; j<colLength; j++){
          arr[i][j] = value++;
        }
      }
      return arr;
    }

    public static void printArray(int arr[][]) {
        //출력 결과를 참고하여 2차원 배열 arr[][]의 모든 원소들을 출력한다.
      for(int i=0; i<arr.length; i++){
        System.out.print("arr["+i+"] ");
        for(int j =0; j < arr[i].length; j++){
          System.out.print(arr[i][j]+" ");
        }
        System.out.println();
      }
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int arr[][];
        
        while(true){ // 아래 과정을 계속 반복 수행한다.
            arr = makeArray(scanner);
            printArray(arr);
            System.out.print("continue? ");
            String str = scanner.next();
            System.out.println();
            //입력된 단어가 "yes"이면 계속 반복 수행하고 "yes"가 아니면 여기서 반복을 중단한다.
            if(!str.equals("yes")) break;
        }
 
        scanner.close();
        System.out.println("Done.");
    }
}

 

3. 대충 이해하기

3-1번 문제와 비교하여 makeArray 메소드만 바뀌었고, 해당 부분도 정방형 배열에서 비정방형 배열로 바뀐 점이 핵심이다.

3-1. 각 행의 시작값 구하기

시작값 구하기

 

비정방형 배열에서 각 행의 시작값을 보면 각 행과 똑같은 것을 볼 수 있다.

0행은 0부터 시작

1행은 1부터 시작

2행은 2부터 시작

즉 코드로는 int value = 각 행의 index; 로 나타낼 수 있었다.

 

3-2. 각 행의 길이 구하기

각 행의 길이는 배열의 사이즈부터 시작해서 각 행을 반복할 수록 1씩 줄어드는 것을 볼 수 있었다.

코드로 나타내면 다음과 같다.

 

 for(int i=0; i<length; i++){ //행을 반복하는 FOR문
        arr[i] = new int[length - i]; //비정방형 배열 생성 (i가 커질수록 점점 작아진다.)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'코딩이야기 > 연습문제' 카테고리의 다른 글

[라이브코딩 연습] JAVA 실습문제 4-2  (0) 2022.11.01
[라이브코딩 연습] JAVA 실습문제 4-1  (0) 2022.11.01
JAVA 실습문제 3-1  (0) 2022.10.28
JAVA 실습문제 3-3  (0) 2022.10.25

1. 문제

/****************************************************************************** *

문제 3-1

******************************************************************************/

// 새로운 프로젝트와 Main.java 소스파일을 만든 후 아래 코드를 복사하여 소스파일에 삽입하라.

// [문제 3-1] 실행 결과를 참고하여 아래 코드를 완성하라.

import ...;

public class Main
{
    public static int[][] makeArray(Scanner s) {
        출력 결과를 참고하여 사용자로부터 정방형 배열 크기("array size? ")를 입력받고 배열을 생성한다. 
        필요한 배열의 원소들을 적절히 초기화한 후 배열을 리턴한다. 
        (초기화하지 않은 배열 원소는 0으로 자동 설정된다.)
    }

    public static void printArray(int arr[][]) {
        출력 결과를 참고하여 2차원 배열 arr[][]의 모든 원소들을 출력한다.
    }
    
    public static void main(String[] args) {
        Scanner scanner = 스캐너 객체 생성;
        int arr[][];
        
        { // 아래 과정을 계속 반복 수행한다.
            arr = makeArray(scanner);
            printArray(arr);
            System.out.print("continue? ");
            문자열 단어 하나를 입력 받음
            System.out.println();
            입력된 단어가 "yes"이면 계속 반복 수행하고 "yes"가 아니면 여기서 반복을 중단한다.
        }
 
        스캐너 객체 닫기;
        System.out.println("Done.");
    }
}




===============================================================================
==  [문제 3-1] 실행 결과
=============================================================================== 
array size? 2
arr[0] 0 1 
arr[1] 2 3 
continue? yes

array size? 3
arr[0] 0 0 1 
arr[1] 0 2 3 
arr[2] 4 5 6 
continue? yes

array size? 4
arr[0] 0 0 0 1 
arr[1] 0 0 2 3 
arr[2] 0 4 5 6 
arr[3] 7 8 9 10 
continue? yes

array size? 5
arr[0] 0 0 0 0 1 
arr[1] 0 0 0 2 3 
arr[2] 0 0 4 5 6 
arr[3] 0 7 8 9 10 
arr[4] 11 12 13 14 15 
continue? no

Done.

 

 

2. 전체코드

import java.util.*;

public class Main
{
    public static int[][] makeArray(Scanner s) {
      System.out.print("array size? ");
      int length = s.nextInt();
      int arr[][] = new int[length][length];
      int number = 1;
      for(int i=0; i<length; i++){
        for(int j=length - i - 1; j<length; j++){
          arr[i][j] = number++;
        }
      }
      return arr;
    }

    public static void printArray(int arr[][]) {
        //출력 결과를 참고하여 2차원 배열 arr[][]의 모든 원소들을 출력한다.
      for(int i=0; i<arr.length; i++){
        System.out.print("arr["+i+"] ");
        for(int j =0; j < arr[i].length; j++){
          System.out.print(arr[i][j]+" ");
        }
        System.out.println();
      }
    }
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int arr[][];
        
        while(true){ // 아래 과정을 계속 반복 수행한다.
            arr = makeArray(scanner);
            printArray(arr);
            System.out.print("continue? ");
            String str = scanner.next();
            System.out.println();
            //입력된 단어가 "yes"이면 계속 반복 수행하고 "yes"가 아니면 여기서 반복을 중단한다.
            if(!str.equals("yes")) break;
        }
 
        scanner.close();
        System.out.println("Done.");
    }
}

 

3. 대충 이해하기

내가 생각하는 가장 핵심 부분은 makeArray 메소드의 값을 집어넣는 부분이다.

결과화면 중 일부 캡쳐

결과를 쭉 나열해서 보니 하나의 공식을 발견할 수 있었는데 해당 공식은 아래와 같다.

값을 삽입할 첫 열(컬럼) : 입력한 사이즈에서 현재 입력될 행을 빼고 -1 (배열의 인덱스는 0부터 시작) 이라는 공식을 발견할 수 있었다.

 

이 내용을 그대로 JAVA로 구현한 것이 makeArray메소드의 이중 for문 부분이다.

'코딩이야기 > 연습문제' 카테고리의 다른 글

[라이브코딩 연습] JAVA 실습문제 4-2  (0) 2022.11.01
[라이브코딩 연습] JAVA 실습문제 4-1  (0) 2022.11.01
JAVA 실습문제 3-2  (0) 2022.10.28
JAVA 실습문제 3-3  (0) 2022.10.25

0. 문제[텍스트]

/******************************************************************************
 * 문제 3-3
 ******************************************************************************/
// 새로운 프로젝트와 Main.java 소스파일을 만든 후 [문제 3-2]에서 작성한 소스코드를 복사해서 삽입하라.
// [문제 3-3] 실행 결과를 참고하여 아래 코드를 완성하라.

public class Main
{
    public static int[][] makeArray(Scanner s) { 기존 코드와 동일 }

    public static void printArray(int arr[][]) { 기존 코드와 동일 }
    
    public static void printArrayElement(Scanner s, int arr[][]) {
        int r = 0, c = 0;
        "dividen? " 와 "divisor? " 를 출력하고 분자와 분모를 각각 입력 받는다.
        분자를 분모로 나눈 몫을 행 변수 r에 저장하고 
        분자를 분모로 나눈 나머지를 열 변수 c에 저장
        arr[r][c] 원소를 출력결과처럼 적절히 출력하고 리턴
        위 과정을 처리하는 도중 예외가 발생할 경우 출력결과처럼 에러 원인을 출력하고 리턴
    }

    public static void main(String[] args) {
        Scanner scanner = 스캐너 객체 생성;
        int arr[][];

 

        arr = makeArray(scanner);
        printArray(arr);
        System.out.println();

 


        { // 아래 과정을 계속 반복 수행한다.

            printArrayElement(scanner, arr);

           System.out.print("continue? ");

           문자열 단어 하나를 입력 받음

           System.out.println();

            입력된 단어가 "yes"이면 계속 반복 수행하고 "yes"가 아니면 여기서 반복을 중단한다.

        }

        스캐너 객체 닫기;

        System.out.println("Done.");

    }
}

1. 문제소개 및 실행예시

JAVA 문제 3-3

 

JAVA 문제 3-3 실행예시

 

2. 전체코드

import java.util.Scanner;
import java.util.InputMismatchException;
  
public class Main{
    public static int[][] makeArray(Scanner s) {
      int size = 0;
      int tmp = 0;
      System.out.print("array size? ");
      size = s.nextInt();
      int size_tmp = size;
      int arr[][] = new int[size][];

      for(int i = 0; i<size; i++)
        arr[i] = new int[size_tmp--];
      
      for(int i = 0; i< size; i++){
        for(int j = 0; j< arr[i].length; j++){
          arr[i][j] = tmp+j+i;
        }
      }
      return arr;
    }

    public static void printArray(int arr[][]) {
      int size = arr.length;
      for(int i = 0; i< size; i++){
        System.out.print("arr["+i+"] ");
        for(int j =0; j < arr[i].length; j++){
          System.out.print(arr[i][j]+" ");
        }
        System.out.println();
      }
      
    }
    public static void printArrayElement(Scanner s, int arr[][]) {
      int r = 0, c = 0;
      try{
        System.out.print("dividen? ");
        int divd = s.nextInt();
        System.out.print("divisor? ");
        int divs = s.nextInt();
        r = divd/divs;
        c = divd%divs;
        System.out.println("arr["+r+"]["+c+"]: "+arr[r][c]);
      }
      catch(ArrayIndexOutOfBoundsException e){
        System.out.println("arr["+r+"]["+c+"]: "+" array index is out of BOUNDS");
      }
      catch(InputMismatchException e){
        System.out.println("input an INTEGER");
        s.nextLine();
      }
      catch(ArithmeticException e){
        System.out.println("divisor is ZERO");
      }
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int arr[][];
                
        arr = makeArray(scanner);
        printArray(arr);
        System.out.println();

        while(true){ 
            printArrayElement(scanner, arr);
            System.out.print("continue? ");
            String s = scanner.next();
            System.out.println();
            if(s.equals("yes"))
              continue;
            else
              break;
        }
 
        scanner.close();
        System.out.println("Done.");
    }
}

 

3. 대충설명

printArrayElement 메소드를 만들면 되는 문제였다.

해당 문제는 try~catch문 에 대해 알고 있으면 쉽게 풀 수 있었다.

try블록 뿐 아니라 catch에서도 접근하기 위해서 try 블록 밖에 선언

② try 안에 있는 내용을 실행하는 도중 에러가 나면 catch문으로 넘어간다.

③ catch문은 선언한 순서대로 실행된다. 즉, 에러가 ArrayIndexOutOfBoundException인지 검사하고 아니라면 InputMismatchException으로 넘어간다.

 

여기에서 친구들이 어려워 했던 건

> 2 b 를입력했을 때이다.

원하는 실행결과는 아래와 같은데 

원하는 실행결과

자꾸 continue? 에서 아무것도 입력하지 안았는데 Done. 이 떠버린다는 것..

잘못된 실행결과

 

 이유는 바로 scanner에 b가 제대로 빠지지 않아서 그렇다.

  1. 사용자가 2 b를 공백으로 구분하여 입력
  2. Scanner의 Buffer에는 2와 b가 저장
  3. scanner.nextInt() 메소드에 의해 차례대로 변수에 저장
  4. int divs = s.nextInt() 코드에서는 b를 int로 읽을 수 없기 때문에 에러가 발생하여 catch문으로 빠지게 된다.
  5. catch문 중에 InputMismatchException 에러이므로 해당 부분이 실행된 후 해당 메소드는 종료된다. (더 이상 실행할 코드가 없음)
  6. 그런데 printArrayElement 메소드 다음에 실행되는 부분에서 scanner.next()를 하게되면?
  7. 아직 빠지지 않은 "b"가 출력이 되어버린다. 그래서 yes와 다르니까 break; 문을 만나 바로 종료되게 된다.

이 부분을 해결하기 위해서는 InputMismatchException 을 처리하는 catch문 쪽에 sc.nextLine()이라고 현재 scanner에 있는 값들을 빼내 주면 해결된다.

'코딩이야기 > 연습문제' 카테고리의 다른 글

[라이브코딩 연습] JAVA 실습문제 4-2  (0) 2022.11.01
[라이브코딩 연습] JAVA 실습문제 4-1  (0) 2022.11.01
JAVA 실습문제 3-2  (0) 2022.10.28
JAVA 실습문제 3-1  (0) 2022.10.28

1. FileReader 객체

FileReader 객체는 웹 애플리케이션이 비동기적으로 데이터를 읽기 위하여 읽을 파일을 가리키는File 혹은 Blob 객체를 이용해 파일의 내용을(혹은 raw data버퍼로) 읽고 사용자의 컴퓨터에 저장하는 것을 가능하게 해줍니다.

File 객체는 <input> 태그를 이용하여 유저가 선택한 파일들의 결과로 반환된 FileList 객체, 드래그 앤 드랍으로 반환된 DataTransfer객체 혹은 HTMLCanvasElement의 mozGetAsFile() API로 부터 얻습니다.

 

1-1. FileReader 메서드

MDN 사이트에서 찾아보니 FileReader에 대한 설명이 자세히 나와있었다. 그 중에 우리가 볼 것은 딱 세가지!!!

FileReader.readAsDataURL  Blob의 내용을 읽어서 URL로 표현 (여기에서 URL은 base64)
FileReader.onload  파일 읽기가 완료되면 호출되는 콜백함수
FileReader.readyState  FileReader의 상태를 나타내는 숫자
  • EMPTY : 0 : 아직 데이터가 로드 되지 않았음.
  • LOADING : 1 : 데이터가 로딩 중.
  • DONE : 2 : 모든 읽기 요청이 완료됨.

 

2. 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CANVAS_1</title>
</head>
<body>
    <input type="file">
    <canvas id="canvas"></canvas>
</body>
</html>

<HTML 코드>

 

window.addEventListener('DOMContentLoaded', (e) => {
        window.$canvas = document.querySelector("#canvas");
        window.ctx = $canvas?.getContext('2d');
        document.querySelector('input')?.addEventListener('change',(e)=>loadFile(e)); //파일 업로드 이벤트는 input의 change로 잡을 수 있다.
    });

    function loadFile(e){
        const file = e.target.files[0];
        console.log(file);
        if(!file.type.match(/image.*/)){ //이미지 파일이 아니라면 필터링
            alert('이미지 파일이 아닙니다.');
            return;
        }
        const reader = new FileReader();
        reader.onload = (e)=>{
            console.log(e);
            const img = new Image();
            img.onload = ()=>{
                $canvas.width = img.width;
                $canvas.height = img.height;
                ctx.drawImage(img,1,1);
            }
            img.src = e.target.result;
        }
        reader.readAsDataURL(file);
    }

<javascript 코드>

메서드 실행순서

  1. input의 change메서드에 이벤트 핸들러를 지정한다. (input의 파일 업로드는 change 이벤트가 발생!)
  2. 사용자가 파일을 업로드
  3. change 이벤트 핸들러인 loadFile() 함수 호출
    1. 이벤트 객체로부터 가져온 file 정보를 기반으로 FileReader의 readAsDataURL메서드 호출 
    2. readAsDataURL메서드가 파일을 모두 읽으면 onload 콜백함수 호출
    3. onload함수 안에서는 Image객체를 생성하고 src를 readeAsDataURL 메서드의 결과물인 Base64로 읽힌 파일(e.target.result) 을 넣어준다.
    4. Image파일의 로드가 모두 끝나면 img.onload 콜백함수가 또 실행되는데 이 함수에서는 canvas의 크기와 canvas에 설정될 이미지를 설정해준다.

 

결과물

 

 

이벤트 객체

위의 코드에서 console.log의 결과물이다.

ProgressEvent객체의 target은 FileReader인데 FileReader의 result를 보면 base64로 인코딩된 file을 볼 수 있고, readerState도 DONE(2) 이 된것을 볼 수 있다.

 

 

 

 

참고사이트 : https://developer.mozilla.org/ko/docs/Web/API/FileReader

 

FileReader - Web API | MDN

FileReader 객체는 웹 애플리케이션이 비동기적으로 데이터를 읽기 위하여 읽을 파일을 가리키는File 혹은 Blob 객체를 이용해 파일의 내용을(혹은 raw data버퍼로) 읽고 사용자의 컴퓨터에 저장하는

developer.mozilla.org

 

'코딩이야기 > JS' 카테고리의 다른 글

[canvas] 캔버스로 모자이크 하기  (0) 2022.11.01
객체 DEEP COPY  (0) 2022.10.17
JavaScript 배열 랜덤 섞기  (0) 2022.10.17

1. 개념 (그냥 스크롤해도 계속 따라 다니면서 그자리 그대로 박혀있는거!)

#고정 레이아웃이란?
-1단 또는 다단 레이아웃에서 상단(header)과 하단(footer) 또는 그 두 영역이 모두 컨텐츠의 높이나 내용에 상관없이 항상 노출 되도록 하는 레이아웃
-컨텐츠의 내용이 길어서 메뉴나 상단 컨텐츠를 고정해주는 것.

#고정 레이아웃 형태를 가진 사이트들
-(네이버 소프트웨어야 놀자) https://www.playsw.or.kr/main
-(네이버 오디오클립) https://audioclip.naver.com
-(라인) https://line.me/ko

 

 

LINE|라인은 언제나 사용자와 함께 합니다.

메신저 앱 그 이상의 경험을 제공합니다. 라인은 새로운 인프라 경험, 새로운 커뮤니케이션 경험을 모두에게 전달하고자 합니다.

line.me

 

소프트웨어야 놀자

Play with AI, Play with DATA

www.playsw.or.kr

 

네이버 오디오클립

즐거움이 들린다, 오디오클립! 당신을 위한 특별한 오디오 콘텐츠를 만나 보세요.

audioclip.naver.com

 

LINE|라인은 언제나 사용자와 함께 합니다.

메신저 앱 그 이상의 경험을 제공합니다. 라인은 새로운 인프라 경험, 새로운 커뮤니케이션 경험을 모두에게 전달하고자 합니다.

line.me

 

2. 코드

<body>
    <div class="wrap">
        <div class="header">header</div>
        <div class="container">
            <div class="content">content</div>
        </div>
        <div class="footer">footer</div>
    </div>
</body>

HTML 구조

 

 

 

	html, body{
            height: 100%;
        }
        .wrap{
            height: 100%;
            min-width: 800px;
            text-align: center;
        }
        .header{
            height: 100px;
            position: fixed;
            background-color: aqua;
            top: 0; left: 0; right: 0;
        }
        .container{
            /* height를 %로 지정하기 위해서는 부모요소로 부터 높이값을 상속받아야한다. */
            min-height: 100%;
            margin: 0 auto;
            margin-top: -100px;
            padding-top: 200px;  /* padding으로 해야 border-box를 사용하여 원하는 레이아웃을 만들 수 있다. */
            box-sizing: border-box;
        }
        .content{
            margin: 0 auto;
            max-width: 1200px;
            height: 300px;
            background-color: brown;
        }
        .footer{
            height: 100px;
            background-color: blue;
        }

CSS구조

 

 

 

레이아웃

 

 

※  reset.css 적용시켜줘야 된다!!

reset.css
0.00MB

 

 

 

이제 하나하나 대충대충 이해한걸 뜯어보자.

 

3. 정리 

3-1. 전체적인 레이아웃

결과본

 

 

※ 주의해야할 점!!!

container

주의해야할 점은 container 영역이 사실 header 영역에서 부터 footer 위까지 쭉 이어져 있다는 것이다. 이는 header가 fixed로 되면서 고정영역으로 되어있기 때문이다.

 

3-2. header

여기에서 중요한 점은 position을 fixed로 설정했다는 것이다.

고정 레이아웃은 상단(header)과 하단(footer) 또는 그 두 영역이 모두 컨텐츠의 높이나 내용에 상관없이 항상 노출 되도록 하는 레이아웃 이므로 fixed가 가장 중요하다고 생각한다.

 

fixed를 적용하면 요소가 해당 영역에 딱 붙어있게 된다. (GIF)

 

 

3-3. container

container css

# header fixed 문제 해결

고정 레이아웃을 공부할 때 가장 감명깊었던것이 container 부분이었다. 그 이유가 header가 fixed가 되면서 container 부분이 header 아래로 들어가버리는 현상을 해결해야했기 때문인데 단순히 margin-top: 100px;(header의 높이가 100px이니까 그만큼 내려주는 것) 을 하면 되는 줄 알았는데, 훨씬 좋은 방법 이 있었다. 

 

[해결방법]

1. 오히려 margin-top : -100px; 을 해준다. (margin은 -를 하면 반대로 움직인다고 생각)

원하는 그림(좌) / margin-100px; 를 했을 때 그림(우)

 

2. padding-top: 200px;

padding-top:200px; 결과

container의 height가 200px; 만큼 더 커진 이유가 중요하다.

예를 들면 해당 예시에서의 container 크기는 969px이다. (html 태그의 height 크기 자체가 969px이고, container는 min-height: 100%; 이기 때문에 부모의 height를 100% 상속받는다.)

하지만 padding-top:200px; 을 하면서 container의 크기가 200px 늘어나버려 1169px; 가 되어버린것.

 

그것을 해결하기 위해 box-sizing: border-box; 를 해준다.

이는 padding 값과 border 값도 포함하여 요소의 height를 지정해주는 속성값이다.

 

3. box-sizing: border-box;

결과적으로 아래와 같은 모양이 된다.

border-box 적용

 

중요한 내용은 다 정리했으니까

끄읕..

'TEMP' 카테고리의 다른 글

윈도우10 자동 드라이버 업데이트 기능 끄기  (0) 2018.08.01

간단한 프로젝트를 할 떄 급하게 GIT에 올려야할 때가 있다.

 

그럴 때는 커맨드를 주로 이용하는 편인데..  너무 가끔씩 쓰다보니까 명령어를 잊버려서 정리도 할 겸 써본다 ㅎㅎ..

 

1. 깃 설치

GIT이 설치되어있지 않다면 먼저 깃을 설치해주자.

GIT 설치주소 : https://git-scm.com

 

Git

 

git-scm.com

 

2. 깃 설치 확인 및 초기화

git version

git version : git이 제대로 설치되었는지 확인 할 겸 부가적으로 버전도 볼수 있다. 개이덕

 

git init

git init : git 저장소를 생성한다. (.git 폴더 생성) 

이때 부터 IDE의 파일 색이 달라지고 파일이름 옆에 U, M 과같은 알파벳이 붙는다. git이 버전을 관리하기 시작했다는 증거이다.

 

3. 원격 저장소 생성

https://github.com/

 

GitHub: Where the world builds software

GitHub is where over 83 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories, review code like a pro, track bugs and feat...

github.com

깃 허브에 로그인하고 들어가면 좌측 상단에 New 라는 초록색 버튼이 보인다. 해당 버튼을 누르면 원격 저장소를 생성할 수 있다.

기본적으로 저기 빨간상자 부분만 입력해주면 쉽게 원격저장소 생성이 가능하다. 소유자와 저장소 이름을 설정하는 부분이다.

 

4. 원격 저장소 설정

4-1. 원격 저장소 주소 복사하기

원격 저장소를 생성했으니 이제 로컬 GIT에게 원격 저장소를 알려줘야한다.

생성된 원격저장소 화면에 들어가서 우측 상단 Code 부분을 클릭하면 원격저장소의 주소가 나온다.

HTTPS 부분의 주소를 복사해준다.

 

4-2. 로컬 GIT에 원격 저장소 추가하기

remote add origin [원격저장소주소]
remote -v

remote add origin 원격저장소주소 : origin이라는 이름으로 원격저장소를 추가한다.

remote -v : 저장되어있는 원격저장소 주소들을 보여준다.

remote -v 를 했을 때 위와 같이 origin이 추가되면 된다.

 

5. 로컬 저장소에 commit하고 원격 저장소에 push 하기

5-1. 로컬 저장소 commit하기

git add moza.html
git status
git commit -m "layout"

일단 로컬 저장소에 commit하기 위해서 git add 명령어를 통해 스테이징 영역에 파일을 넣어준다.

스테이징 영역에는 버전을 만들 파일들이 대기하는 장소라고 생각하면 될것같다.

 

git status로 add한 파일들이 잘 들어갔는지 확인하고 확인이 끝나면 

git commit 명령어로 커밋해준다. 위의 예시에서 "layout"은 커밋 메시지이다. (해당 버전에 대한 설명)

 

이때 커밋을 완료하면 master 브랜치가 자동으로 생성될 것이다.

이렇게 브랜치가 생성된 상태에서 마지막으로 원격 저장소에 PUSH해주면 된다.

 

5-2. 원격 저장소 PUSH하기

git push origin master

 

근데 여기서 git을 최초 설치하여 사용자 정보가 설정되어있지 않다면 Authentication failed for~ 에러가 뜬다.

그럴떄는 당황하지 말고 설정해주면 된다.

* 사용자 설정

git config user.name 사용자명
git push origin master

다시 푸쉬를 시도하면 비밀번호를 입력하라고 뜨는데 그때 비밀번호 혹은 Token을 입력해주면 된다.

※발급 받은 토큰이 없다면 ... 나중에 또 하는 방법 만들어야지

 

+ Recent posts