본문 바로가기

프로젝트 개발기/Status 200 ( Team Project )

7. TEAM 프로젝트: 캘린더 기능 구현 - 스케줄 (1)


상세한 개발 내역을 작성할려고 했으나, 여러 번의 디버그가 있었고 개발 단계에서 변경되는 점 또한 많았다. 

때문에 완성된 캘린더를 기능 별로 정리하고, 개선점을 작성하려고 한다. 

(TimeLine에 작성해 봤으나 글이 한눈에 들어오지 않는다는 단점이 있어서 방법을 바꿨다.)


 

1. 스케줄 기능 구현

스케줄은 계정을 기반으로 하되, 그룹에 따라 표현되는 스케줄의 모양이 다르다는 차이점을 가진다. 

또한 날짜에 따라 모양이 표현되어야 하므로, 영역에 따른 표시 알고리즘이 필요하다. 

단순한 수를 비교하는 알고리즘이지만, 날짜는 년도, 월, 일을 포함하기 때문에 if 문을 여러 차례 사용하여 데이터를 검증해야 한다. 

때문에 우선 스케줄에 대한 기본 기능을 먼저 작성하고 날짜 표시 알고리즘에 대해서는 '캘린더 기능 구현 - 스케줄 (2)'에서 포스트하겠다.

 

스케줄 기능에는 다음과 같은 기능이 표현되어야 한다.

  • 스케줄 추가 기능
  • 스케줄 수정 기능
  • 스케줄 삭제 기능
  • 스케줄 보기 기능
  • 스케줄 권한자에 따른 처리 제한
  • 편의성을 위한 기능

 

2. DTO 제작 

package DTO;

public class ScheduleDTO {

	private String num;
	private String title;
	private String content;
	private String start;
	private String end;
	private String color;
	private String writer;
	private String groupnum;

	public String getContent() {
		if(content.equals(null)) {
			content = "";
		}
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getNum() {
		return num;
	}
	public void setNum(String num) {
		this.num = num;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getStart() {
		return start;
	}
	public void setStart(String start) {
		this.start = start;
	}
	public String getEnd() {
		return end;
	}
	public void setEnd(String end) {
		this.end = end;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public String getGroupnum() {
		return groupnum;
	}
	public void setGroupnum(String groupnum) {
		this.groupnum = groupnum;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
}

DTO는 Data Transfer Object를 말하는데, 하나의 오브젝트를 다루기 위해서 데이터를 저장하는 Class를 말한다.

Java에서는 Private를 사용해서 접근 권한을 제한하는데, 이는 데이터가 불필요하게 혼선되어 수정되는 상황을 방지하기 위해서이다. 

이러한 기능을 싱글톤 패턴이라고 하며, 각각의 사용자가 고유하게 가져야하는 데이터의 무결성을 유지하기 위해 사용한다. 

스케줄에는 연관된 데이터 항목이 수정자, 그룹으로 나뉘기 때문에 그룹에 대한 구조가 궁금하다면 '캘린더 기능 구현 - 그룹'을 참조하자. 

 

3. DAO 제작 

package DAO;
import java.sql.*;
import java.util.*;

import DTO.GroupDTO;
import DTO.ScheduleDTO;

public class ScheduleDAO {
	private ScheduleDAO(){
		
	}
	
	private static ScheduleDAO instance = new ScheduleDAO();
	
	public static ScheduleDAO getInstance(){
		return instance;
	}
	
	public Connection getConnection(){
		Connection conn=null;
		String url="jdbc:mysql://127.0.0.1:3306/status200";
		String db_id="root";
		String db_pw="iotiot";
		
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn=DriverManager.getConnection(url, db_id, db_pw);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Schedule DAO Error **********"+e);	
		}

		return conn;
	}
	public static void close(Connection conn, Statement stmt, ResultSet rs){
		try{
			if(rs!=null){
				rs.close();
			}
			if(stmt!=null){
				stmt.close();
			}
			if(conn!=null){
				conn.close();
			}
		}
		catch(Exception e){
			System.out.println("Close Error(val ==3) : "+ e);
		}
	}
	
	public static void close(Connection conn, Statement stmt){
		try{
			if(stmt!=null){
				stmt.close();
			}
			if(conn!=null){
				conn.close();
			}
		}
		catch(Exception e){
			System.out.println("Close Error(val == 2) : "+ e);
		}
	}
	
	// Schedule add to table. 스케줄 인설트  
	public void scheduleInsert(ScheduleDTO sDTO){
		
		String sql="insert into schedule(title, content, start, end, writer, groupnum, color) values(?,?,?,?,?,?,?)";
		Connection conn=null;
		PreparedStatement pstmt=null;
		
		try{
			conn=getConnection();
			pstmt=conn.prepareStatement(sql);
			pstmt.setString(1, sDTO.getTitle());
			pstmt.setString(2, sDTO.getContent());
			pstmt.setString(3, sDTO.getStart());
			pstmt.setString(4, sDTO.getEnd());
			pstmt.setString(5, sDTO.getWriter());
			pstmt.setString(6, sDTO.getGroupnum());
			pstmt.setString(7, sDTO.getColor());

			System.out.println(pstmt);
			pstmt.executeUpdate();

		}
		catch(Exception e)
		{
			System.out.println("ScheduleDAO> Insert Error: "+e);
		}
		finally
		{
			close(conn, pstmt);
		}
	}
	//스케줄 딜리트 
	public void scheduleDelete(ScheduleDTO sDTO){
		String sql ="delete from schedule where num = ?";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try
		{
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, sDTO.getNum());
			pstmt.executeUpdate();
			
		}
		catch(Exception e){
			System.out.println("ScheduleDAO> Delete Error : "+ e);
		}
		finally{
			close(conn, pstmt);
		}
	}
	// 스케줄 업데이트 
	public void scheduleUpdate(ScheduleDTO sDTO){
		String sql="update schedule set title=?, content=?, start=?, end=?, color=?, groupnum=? where num=?";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try{
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setString(1, sDTO.getTitle());
			pstmt.setString(2, sDTO.getContent());
			pstmt.setString(3, sDTO.getStart());
			pstmt.setString(4, sDTO.getEnd());
			pstmt.setString(5, sDTO.getColor());
			pstmt.setString(6, sDTO.getGroupnum());
			pstmt.setString(7, sDTO.getNum());
			System.out.println(pstmt);
			pstmt.executeUpdate();
		}
		catch(Exception e){
			System.out.println("ScheduleDAO > UPDATE Error : "+ e);
		}
		finally{
			close(conn, pstmt);
		}
	}
	
	// 스케줄 리스트를 반환함, 다수의 스케줄을 확인함 
	public List<ScheduleDTO> scheduleList(GroupDTO gDTO){
		// 변수를 Group으로 받아서 그룹 데이터를 기준으로 조회함 
		// 이렇게 조회해야 Group 별로 스케줄을 분류하고 '보기 및 끄기'를 구현할 수 있음 
		List<ScheduleDTO> list= new ArrayList<ScheduleDTO>();
		
		String sql="select * from schedule where groupnum=? order by num desc";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, gDTO.getGroupnum());
			
			rs = pstmt.executeQuery();
			while(rs.next())
			{	
				ScheduleDTO sDTO = new ScheduleDTO();
				
				sDTO.setNum(rs.getString("num"));
				sDTO.setTitle(rs.getString("title"));
				sDTO.setContent(rs.getString("content"));
				sDTO.setStart(rs.getString("start"));
				sDTO.setEnd(rs.getString("end"));
				sDTO.setColor(rs.getString("color"));
				sDTO.setWriter(rs.getString("writer"));
				sDTO.setGroupnum(rs.getString("groupnum"));
				
				list.add(sDTO);
			}
		}
		catch(Exception e){
			System.out.println("Schedule DAO> Select Error(val == 1) : "+ e);
		}
		finally{
			close(conn, pstmt, rs);
		}
		return list;
	}
	
	// 스케줄을 찾을 경우 반환하는 데이터, 단어를 Like로 지정하여 일치하면 찾음 
	// 다만 속해있는 그룹이 아니면 찾아서는 안됨 
	public List<ScheduleDTO> scheduleListSearch(GroupDTO gDTO, String word){
		
		List<ScheduleDTO> list= new ArrayList<ScheduleDTO>();
		
		String searchWord = "%"+word+"%";
		String sql="select * from schedule where groupnum = ? and (title like ? or content like ?) limit 10";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try
		{
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, gDTO.getGroupnum());
			pstmt.setString(2, searchWord);
			pstmt.setString(3, searchWord);
			
			rs = pstmt.executeQuery();
			System.out.println(pstmt);
			while(rs.next())
			{
				ScheduleDTO sDTO = new ScheduleDTO();
				
				sDTO.setNum(rs.getString("num"));
				sDTO.setTitle(rs.getString("title"));
				sDTO.setContent(rs.getString("content"));
				sDTO.setStart(rs.getString("start"));
				sDTO.setEnd(rs.getString("end"));
				sDTO.setColor(rs.getString("color"));
				sDTO.setWriter(rs.getString("writer"));
				sDTO.setGroupnum(rs.getString("groupnum"));
				
				list.add(sDTO);
			}
		}
		catch(Exception e){
			System.out.println("Schedule DAO> Select Error(val == 3) : "+ e);
		}
		finally{
			close(conn, pstmt, rs);
		}
		return list;
	}
}

DAO는 Data Access Object를 말하는데, 데이터 베이스에 접근하기 위한 객체를 말한다. 

DAO는 사전에 정의된 메서드를 사용하기 때문에, 모든 사용자가 같은 DAO를 사용하는 것이 좋다. 

때문에 getInstance를 사용하여, DAO를 할당해준다. 

 

스케줄 자체에서 그룹에 대한 식별자(Groupnum)을 가지고 있어서, 다른 테이블과 Join 하지 않고도 조회 및 수정이 가능하다. 

사용자가 속한 그룹의 데이터는 별도의 테이블에서 관리하고 있고, 해당 테이블의 Select 값을 기반으로 SQL을 사용해야하기 때문에 스케줄에서 이러한 조작 과정이 필요하지는 않다. 

 

4. 기능 세부 정보

1) 기본 설정

// 캘린더에 대한 XmlHttpRequest
var XHRCalendar;
function createXHRCalendar(){
    if(window.ActiveXObject){ 
        XHRCalendar=new ActiveXObject("Microsoft.XMLHTTP");
    }
    else if(window.XMLHttpRequest){
        XHRCalendar=new XMLHttpRequest();
    }
}

// JSON SCHEDULE 객체 데이터 생성 
function createJsonSchedule(num, title, content, start, end, color, writer, groupnum){
    let json = {
        num: num,
        title: title,
        content: content,
        start: start,
        end: end,
        color: color,
        writer: writer,
        groupnum: groupnum
    }
    return json;
}

내가 작성하는 일반 코드들에선 let을 주로 사용하는데 XHR에는 var를 사용했다.

이유는 let을 사용하면 스코프 범위가 호이스팅 단계에서 제한적으로 적용되는데, 이에 따라 펑션의 위치나 스코프에 따른 참조 위치가 중요하기 때문이다.

Loading 단계에서 let으로 설정한 XHR들은 화면 구성 단계에서 변수 스코프를 벗어나버린다. 때문에 참조 오류가 발생해버리고, 코드 오류로 Java Script의 구동이 불가능하다. 이러한 이유로 var을 사용하였다. 

 

 

2) 스케줄 추가 및 수정 기능

a. 서블렛 

package ServletCalendar;

import java.io.BufferedReader;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import DAO.ScheduleDAO;
import DTO.ScheduleDTO;

import org.json.simple.*;
import org.json.simple.parser.*;

@WebServlet("/scheduleInsert")
public class scheduleInsert extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		response.getWriter().append("Served at: ").append(request.getContextPath());
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		
		String json = readJSON(request);
		System.out.println(json); 
		JSONObject data = objJSON(json);
		
		String num=(String) data.get("num");
		String title=(String) data.get("title");
		String content=(String) data.get("content");
		String start=(String) data.get("start");
		String end=(String) data.get("end");
		String color=(String) data.get("color");
		String writer=(String) data.get("writer");
		String groupnum=(String) data.get("groupnum");
		
		ScheduleDTO sDTO = new ScheduleDTO();
		sDTO.setNum(num);
		sDTO.setTitle(title);
		sDTO.setContent(content);
		sDTO.setStart(start);
		sDTO.setEnd(end);
		sDTO.setColor(color);
		sDTO.setWriter(writer);
		sDTO.setGroupnum(groupnum);
		
		ScheduleDAO sDAO = ScheduleDAO.getInstance();
		
		if(num.equals("")) {;
			sDAO.scheduleInsert(sDTO);	
		}
		else {
			sDAO.scheduleUpdate(sDTO);
		}
	}
	
	protected String readJSON(HttpServletRequest request) { 
		StringBuffer json = new StringBuffer(); 
		String line = null;
		
		try { 
			BufferedReader reader=request.getReader();

			while((line=reader.readLine())!=null){ 
				json.append(line); 
			}
		}
		catch(Exception e) {
			System.out.println("JSON 파일을 읽어오던 중 오류 발생");
		}
		return json.toString(); 
	}
	
	protected JSONObject objJSON(String str) {
		Object obj=null;
		JSONObject json=null;
		System.out.println(str);
		try {
			JSONParser parser = new JSONParser();
			obj=parser.parse(str);
			json=(JSONObject)obj;
		}
		catch(Exception e) {
			System.out.println("JSON 변환 중 오류 발생: "+e);
		}
		return json;
	}

}

 

b. AJAX

function addGroupSchedule(){
    let jsonSchedule;

    let num = document.getElementsByClassName("scheduleFormNum")[0].value;
    let title = document.getElementsByClassName("scheduleFormTitle")[0].value;
    let content = document.getElementsByClassName("scheduleFormContent")[0].value;
    let start = document.getElementsByClassName("scheduleFormStart")[0].value;
    let starttime = document.getElementsByClassName("scheduleFormStartTime")[0].value;
    let end = document.getElementsByClassName("scheduleFormEnd")[0].value;
    let endtime = document.getElementsByClassName("scheduleFormEndTime")[0].value;
    let color = document.getElementsByClassName("scheduleFormColor")[0].value;
    let writer = userKey;
    let groupnum = document.getElementsByClassName("scheduleFormGroupSelect")[0].value;

    //20211010/15:15
    start+="/"+starttime;
    end+="/"+endtime;

    jsonSchedule = JSON.stringify(createJsonSchedule(num, title, content, start, end, color, writer, groupnum));

    if(typeof(date)=="undefined"){
        let input = document.getElementsByClassName("calendarHeadDateInfo")[0];
        let inputYear = parseInt(input.value.substring(0,4));
        let inputMonth = parseInt(input.value.substring(4,6));
        let inputDay = parseInt(input.value.substring(6,8));

        date = getThisDay(inputYear, inputMonth, inputDay, 0, 0);
    }
    createXHRCalendar();

    XHRCalendar.onreadystatechange=function(){
        if(XHRCalendar.readyState==4){
            if(XHRCalendar.status==200){
                getGroupSchedule(userKey, date);
            }
        }
    };
    XHRCalendar.open("POST", "scheduleInsert", true);
    XHRCalendar.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    XHRCalendar.send(jsonSchedule);
}

 

AJAX를 기반으로 통신을 진행한다. 

서블렛에서는 해당 통신의 데이터 중 num가 있는 지를 확인하고, 만약 num가 있다면 Update를 진행한다.

해당 방법으로 진행하면 JavaScript에서 검증을 통해 Update 여부를 판단하지 않아도 Java에서 쉽게 처리가 가능하다.

 

 

2) 스케줄 삭제 기능

a. 서블렛 

package ServletCalendar;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import DAO.ScheduleDAO;
import DTO.ScheduleDTO;

@WebServlet("/scheduleDelete")
public class scheduleDelete extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		String num = request.getParameter("num");
		
		ScheduleDAO sDAO = ScheduleDAO.getInstance();
		ScheduleDTO sDTO = new ScheduleDTO();
		sDTO.setNum(num);
		
		sDAO.scheduleDelete(sDTO);
	}
}

 

b. AJAX

function delGroupSchedule(date){
    let data = tempData;
    createXHRCalendar();

    if(typeof(date)=="undefined"){
        let input = document.getElementsByClassName("calendarHeadDateInfo")[0];
        let inputYear = parseInt(input.value.substring(0,4));
        let inputMonth = parseInt(input.value.substring(4,6));
        let inputDay = parseInt(input.value.substring(6,8));

        date = getThisDay(inputYear, inputMonth, inputDay, 0, 0);
    }

    XHRCalendar.onreadystatechange=function(){
        if(XHRCalendar.readyState==4){
            if(XHRCalendar.status==200){
                quitScheduleDetail();
                getGroupSchedule(userKey, date);
            }
        }
    };
    XHRCalendar.open("POST", "scheduleDelete", true);
    XHRCalendar.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    XHRCalendar.send("num="+data.num);
}

 

 

3) 스케줄 보기 기능

a. 서블렛 

package ServletCalendar;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.simple.*;
import org.json.simple.JSONArray;

import DAO.GroupDAO;
import DAO.ScheduleDAO;
import DTO.GroupDTO;
import DTO.ScheduleDTO;

@WebServlet("/scheduleSelect")
public class scheduleSelect extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@SuppressWarnings("unchecked")
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		
		String userKey = request.getParameter("userKey");
		
		ScheduleDAO sDAO = ScheduleDAO.getInstance();
		GroupDAO gDAO = GroupDAO.getInstance();
		
		List<GroupDTO> glist = gDAO.groupList(userKey);
		List<ScheduleDTO> slist= new ArrayList<ScheduleDTO>();
		JSONArray jsons = new JSONArray();
		
		for(int i = 0; i<glist.size(); i++) {
			
			JSONArray schedules = new JSONArray();
			
			JSONObject json = new JSONObject();
			JSONArray members = new JSONArray();
			JSONArray modifiers = new JSONArray();
			slist=sDAO.scheduleList(glist.get(i));
			
			json.put("groupnum", glist.get(i).getGroupnum().toString());
			json.put("groupname", glist.get(i).getGroupname().toString());
			json.put("groupcolor", glist.get(i).getGroupcolor().toString());
			json.put("master", glist.get(i).getMaster().toString());
			json.put("searchable", glist.get(i).getSearchable().toString());
			
			for(int j = 0; j<glist.get(i).getMembers().length; j++) {
				members.add(glist.get(i).getMembers()[j]);
			}
			
			json.put("members", members);
			
			for(int j = 0; j<glist.get(i).getModifiers().length; j++) {
				modifiers.add(glist.get(i).getModifiers()[j]);
			}
			json.put("modifiers",modifiers);
			
			
			for(int j = 0; j<slist.size(); j++) {
				JSONObject json1 = new JSONObject();
				json1.put("num", slist.get(j).getNum().toString());
				json1.put("title", slist.get(j).getTitle().toString());
				json1.put("start", slist.get(j).getStart().toString());
				json1.put("end", slist.get(j).getEnd().toString());
				json1.put("content", slist.get(j).getContent().toString());
				json1.put("writer", slist.get(j).getWriter().toString());
				json1.put("color", slist.get(j).getColor().toString());
				
				schedules.add(json1);
			}
			json.put("schedule", schedules);
			jsons.add(i, json);
		}
		
		response.setContentType("application/json");
		response.setCharacterEncoding("utf-8");
		PrintWriter out = response.getWriter();
		out.print(jsons.toString());
		out.flush();
		
	}
}

 

b. AJAX 

function getGroupSchedule(userKey, date){
    let scheduleTitleInSpans = document.getElementsByClassName("scheduleTitleInSpan");
    let groupDivs = [];
    let selectForm = document.getElementsByClassName("selectForm")[0];
    let jsons;
    createXHRCalendar();

    XHRCalendar.onreadystatechange=function(){
        if(XHRCalendar.readyState==2){
            toDoList();
        }
        if(XHRCalendar.readyState==4){

            if(XHRCalendar.status==200){
                clearMonthBoxBody();
                jsons = JSON.parse(XHRCalendar.responseText, "text/json");

                for(let i = 0; i < Object.keys(jsons).length; i++){
                    console.log(jsons);
                    // 제이손 형태 데이터를 그룹 별로 구분하고, 이걸 다시 스케줄 별로 구분함 
                    // 이렇게 생성된 데이터를 기준으로 스케줄 그림 
                    for(let j = 0; j < Object.keys(jsons[i].schedule).length; j++){
                        let temp = {
                            groupnum: jsons[i].groupnum,
                            groupname: jsons[i].groupname,
                            groupcolor: jsons[i].groupcolor,
                            members: jsons[i].members,
                            modifiers: jsons[i].modifiers,

                            num: jsons[i].schedule[j].num,
                            title: jsons[i].schedule[j].title,
                            start: jsons[i].schedule[j].start,
                            end: jsons[i].schedule[j].end,
                            content: jsons[i].schedule[j].content,
                            writer: jsons[i].schedule[j].writer,
                            color: jsons[i].schedule[j].color
                        } 
                        scheduleData.push(temp);
                    }

                    // 템프 DIV를 모아서 그룹 DIV로 만들고 이 데이터로 그룹 멤버 모양을 표시함
                    let tempDiv = {
                        groupnum: jsons[i].groupnum,
                        groupname: jsons[i].groupname,
                        members: jsons[i].members,
                        master: jsons[i].master,
                        searchable: jsons[i].searchable,
                        groupcolor: jsons[i].groupcolor,
                        modifiers: jsons[i].modifiers
                    }
                    groupDivs.push(tempDiv);
                }
                // 그룹 Div로 그룹 모양 구현 
                createGroupDivs(groupDivs); // 그룹 엘레먼트 생성, 그룹 참조

                if(selectForm.value=="Y"){
                    createYearSchedule(scheduleData);
                }
                else if(selectForm.value=="M"){
                    // 스케줄 먼저 그림
                    createScheduleElement(scheduleData);
                    // 스케줄 그리고 각 첫 요소 파악해서 첫요소 길이를 차등 부여
                    checkMonthScheduleFirst(); 
                    // 배열 초기화하지 않으면 같은 스케줄이 해당 함수 실행시마다 추가됨
                    viewScheduleElementFlag();
                    // 스케줄의 영역 차지 박스를 바꿈 > 추후 모양 CSS에 따라 필요없을 수 있음
                    checkFirstElement();
                }
                else if(selectForm.value=="D"){

                }

                // 배열 초기화하지 않으면 같은 스케줄이 해당 함수 실행시마다 추가됨
                scheduleData = []; 
                checkInvite();
            }
        }
    }
    XHRCalendar.open("POST", "scheduleSelect", true);
    XHRCalendar.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    XHRCalendar.send("userKey="+userKey);
}

스케줄의 추가, 삭제, 수정, 보기는 스케줄이라는 서비스를 다루기 위한 기본 기능이다.

보기에서 다양한 데이터를 정제하고, 함수를 사용하는 것은 해당 기능이 '그룹'을 기반으로 구현되었기 때문이다.

그룹에 속한 인원은 그룹에 따라 스케줄을 취사 선택해서 볼 수 있어야하고, 또한 스케줄을 추가할 때 그룹에 맞게 추가할 수 있어야 한다.

 

또한 연간, 월간에 따라 각각 표현해야할 모양과 스케줄 표시가 상반된다.

각각의 알고리즘은 스케줄 표시에만 사용되지만, 해당 알고리즘이 복잡하기 때문에 펑션으로 만들어 이를 호출하였다. 

 

아래의 더보기를 통해 사용한 함수를 확인할 수 있다.

 

더보기
function createYearSchedule(scheduleData){

    let yearBoxBodys = document.getElementsByClassName("yearBoxBody");

    for(let i = 0; i < scheduleData.length; i++){

        let startYear = scheduleData[i].start.substring(0, 4);
        let startMonth = scheduleData[i].start.substring(5, 7);
        let startDay = scheduleData[i].start.substring(8, 10);

        let endYear = scheduleData[i].end.substring(0, 4);
        let endMonth = scheduleData[i].end.substring(5, 7);
        let endDay = scheduleData[i].end.substring(8, 10);

        for(let j = 0; j < yearBoxBodys.length; j++){
            let yfd = yearBoxBodys[j].getElementsByClassName("dateTag")[0].value;
            let yfdYear =  yfd.substring(0, 4);
            let yfdMonth =  yfd.substring(4, 6);
            let yfdDay =  yfd.substring(6, 8);


            if(startYear>yfdYear){
                // 일정 시작 안함
                // 건너감 
            }
            else if(startYear==yfdYear){
                // 일정 시작을 했음 
                if(endYear>yfdYear){
                    // 월 하고 날 찾고 그뒤로 다들어감 
                    if(startMonth>yfdMonth){
                        // 작동 안함 
                    }
                    else if(startMonth==yfdMonth){
                        // 년간폼이면 그냥 넣음 일을 비교해서
                        if(startDay>yfdDay){
                            // 안그림 
                        }
                        else if(startDay<=yfdDay){
                            // 일정 시작 > 년도 끝까지 // 시간을 비교후 
                        }
                        else if(startDay<yfdDay){
                            // 일정 시작 > 년도 끝까지 // 종일 
                        }
                    }
                    else if(startMonth<yfdMonth){
                        // 시작 함 
                        // 다 그림 // 종일 
                    }
                }
                else if(endYear==yfdYear){
                    // 월하고 날을 비교 해서 구간을 정해야함 
                    if(startMonth>yfdMonth){
                        // 안함 // 시작 안함 
                    }
                    else if(startMonth==yfdMonth){
                        // 년간폼이면 그냥 넣음 일을 비교해서
                        if(endMonth>yfdMonth){
                            // 전체 그림 > 일간은 종일 
                            if(startDay>yfdDay){
                                // 시작 안함 
                            }
                            else if(startDay==yfdDay){
                                // 시작 함 > 월 끝 // 시작 날짜 시간 비교 
                                createYearElement(yearBoxBodys[j], scheduleData[i]);
                            }
                            else if(startDay<yfdDay){
                                // 시작함 > 월 끝 // 종일 
                                createYearElement(yearBoxBodys[j], scheduleData[i]);
                            }
                        }
                        else if(endMonth==yfdMonth){
                            // 시작날짜, 끝 날짜를 비교해서 구간을 설정 
                            if(startDay>yfdDay){
                                // 시작 안함 
                            }
                            else if(startDay==yfdDay){
                                // 시작 함 > 끝 날짜 탐색 // 시간봐야함 
                                if(endDay>yfdDay){
                                    // 그림  //
                                    createYearElement(yearBoxBodys[j], scheduleData[i]);
                                }
                                else if(endDay==yfdDay){
                                    // 그림
                                    createYearElement(yearBoxBodys[j], scheduleData[i]);

                                }
                                else if(endDay<yfdDay){
                                    // 안그림 > 끝난 일정 
                                }
                            }
                            else if(startDay<yfdDay){
                                // 시작함 > 끝나는 날짜까지 가는중 
                                if(endDay>yfdDay){
                                    // 그림 
                                    createYearElement(yearBoxBodys[j], scheduleData[i]);
                                }
                                else if(endDay==yfdDay){
                                    // 그림
                                    createYearElement(yearBoxBodys[j], scheduleData[i]);
                                }
                                else if(endDay<yfdDay){
                                    // 안그림 > 끝난 일정 
                                }
                            }
                        }
                        else if(endMonth<yfdMonth){
                            // 일정이 끝남 
                        }
                    }
                    else if(startMonth<yfdMonth){
                        // 일을 비교하고 구간 
                        if(endMonth>yfdMonth){
                            // 전체 그림 	
                            createYearElement(yearBoxBodys[j], scheduleData[i]);
                        }
                        else if(endMonth==yfdMonth){
                            // 날짜비교> 언제 끝나는지 찾음 
                            if(endDay>yfdDay){
                                // 그림 
                                createYearElement(yearBoxBodys[j], scheduleData[i]);
                            }
                            else if(endDay==yfdDay){
                                // 그림
                                createYearElement(yearBoxBodys[j], scheduleData[i]);
                            }
                            else if(endDay<yfdDay){
                                // 안그림 > 끝난 일정 
                            }
                        }
                        else if(endMonth<yfdMonth){
                            // 일정이 끝남 
                        }
                    }
                }
                else if(endYear<yfdYear){
                    // 불가능한 경우 
                }
            }
            else if(startYear<yfdYear){
                // 일정 시작을 했음 
                if(endYear>yfdYear){
                    // 전체 들어감 (년도에 한해서)
                    createYearElement(yearBoxBodys[j], scheduleData[i]);
                }
                else if(endYear==yfdYear){
                    // 뭘 하고 날짜 비교해서 끝나는 구간 설정 
                    if(endMonth>yfdMonth){
                        // 전체 
                        createYearElement(yearBoxBodys[j], scheduleData[i]);
                    }
                    else if(endMonth==yfdMonth){
                            // 날짜 비교 
                        if(endDay>yfdDay){
                            // 그려야 함 
                            createYearElement(yearBoxBodys[j], scheduleData[i]);
                        }
                        else if(endDay==yfdDay){
                            // 그려야 함/ 끝나는 시점
                            createYearElement(yearBoxBodys[j], scheduleData[i]);
                        }
                        else if(endDay<yfdDay){
                            // 안그림 
                        }
                    }
                    else if(endMonth<yfdMonth){
                            // 일정이 끝남 
                    }
                }
                else if(endYear<yfdYear){
                    // 이미 끝난 일정 // 동작 안함 
                }
            }
        }
    }
}
더보기
function createYearElement(yearBoxBodys, scheduleData){

    let numberChilds = yearBoxBodys.parentNode.childNodes.length;

    let p = yearBoxBodys.parentNode;
    let v;
    let c;
    let cc;
    let ccc;

    v = document.createElement("div");
    v.classList.add("yearformEl");

    c = document.createElement("div");
    c.classList.add("yearFormSC");
    c.innerHTML = ".";
    v.appendChild(c);

    c = document.createElement("div");
    c.classList.add("scHidden");
    c.setAttribute("style", "display: none;")

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("groupNum"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.groupnum);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("groupName"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.groupname);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("groupColor"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.groupcolor);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("modifier"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.modifier);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleNum"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.num);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleTitle"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.title);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleStart"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.start);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleEnd"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.end);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleContent"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.content);

    c.appendChild(cc);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleWriter"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.writer);

    cc = document.createElement("input");
    cc.classList.add("scInfo"); 
    cc.classList.add("scheduleColor"); 
    cc.setAttribute("type", "hidden");
    cc.setAttribute("value", scheduleData.color);

    c.appendChild(cc);

    v.appendChild(c);
    p.insertBefore(v, p.firstChild);
}
더보기
// 스케줄 요소를 제작
// 스케줄 데이터에 따라 스케줄이 그려질 영역을 구현함
// 스케줄 시작 및 끝 데이터를 각각 비교하며 경우의 수를 따져야함
// if 문 사용이 많을 수 밖에 없음
function createScheduleElement(scheduleData){
    let dateTags = document.getElementsByClassName("dateTag");


    for(let i = 0; i < scheduleData.length; i++){
        // 추후 팀원 중 주 및 일 일정은 day 변수까지 사용
        let startYear = parseInt(scheduleData[i].start.substring(0,4));
        let startMonth = parseInt(scheduleData[i].start.substring(5,7));
        let startDay = parseInt(scheduleData[i].start.substring(8,10));

        let endYear = parseInt(scheduleData[i].end.substring(0,4));
        let endMonth = parseInt(scheduleData[i].end.substring(5,7));
        let endDay = parseInt(scheduleData[i].end.substring(8,10));

        // 이어와 몬스에 따라 리턴해서 불필요한 경우 포문이 계속 돌게함 
        for(let j = 0; j < dateTags.length; j++){

            let dateTagYear = parseInt(dateTags[j].value.substring(0,4));
            let dateTagMonth = parseInt(dateTags[j].value.substring(4,6));
            let dateTagDay = parseInt(dateTags[j].value.substring(6,8));

            if(dateTagYear>startYear){
                if(dateTagYear<endYear){
                    // 가운데 끼는 상황, 전체 반복해서 월에 다 표시
                    createScheduleBox(scheduleData[i], dateTags[j]);
                }
                else if(dateTagYear==endYear){
                    if(dateTagMonth>endMonth){
                        // 일정 끝남: 몬스가 엔드 몬스보다 뒤면 일정이 끝났음
                    }
                    else if(dateTagMonth<endMonth){
                        createScheduleBox(scheduleData[i], dateTags[j]);
                    }
                    else if(dateTagMonth==endMonth){
                        if(dateTagDay>endDay){

                        }
                        else if(dateTagDay<=endDay){
                            createScheduleBox(scheduleData[i], dateTags[j]);
                        }
                    }
                }
                else if(dateTagYear>endYear){
                    // 끝난 일정
                }
            }
            else if(dateTagYear==startYear){
                if(dateTagYear<endYear){
                    // 가운데 끼는 상황, 전체 반복해서 월에 다 표시
                    if(dateTagMonth<startMonth){

                    }
                    else if(dateTagMonth>startMonth){
                        createScheduleBox(scheduleData[i], dateTags[j]);
                    }
                    else if(dateTagMonth==startMonth){
                        if(dateTagDay<startDay){

                        }
                        else if(dateTagDay=>startDay){
                            createScheduleBox(scheduleData[i], dateTags[j]);
                        }
                    }
                }
                else if(dateTagYear==endYear){
                    if(dateTagMonth<startMonth){
                        // 일정이 시작 안한 상태랑 같음 >
                    }
                    else if(dateTagMonth>startMonth){
                        if(dateTagMonth>endMonth){
                            // 일정 끝남 
                        }
                        else if(dateTagMonth==endMonth){
                            // 날짜를 비교함
                            if(dateTagDay>endDay){
                                // 끝 날짜보다 크면 그리지 말아야함
                            }
                            else if(dateTagDay<=endDay){
                                // 같거나 끝나짜가 크면 그려야함
                                createScheduleBox(scheduleData[i], dateTags[j]);
                            }
                        }
                        else if(dateTagMonth<endMonth){
                            // 현재 달이 끝나는 달보다 크므로 모두 그려줌
                            createScheduleBox(scheduleData[i], dateTags[j]);
                        }
                    }
                    else if(dateTagMonth==startMonth){
                        // 일정 달이 겹치므로 일 비교해야함 
                        // 해당 일정이 해당 달에 시작하기 때문에 값이 일치하는 부분에서 포문으로 한번 그려주면 끝
                        if(dateTagMonth==endMonth){
                            if(dateTagDay<startDay){
                                // 일정 시작 안함 
                            }
                            else if(dateTagDay=>startDay){
                                // 일정은 시작됨, 마지막 날 비교
                                if(dateTagDay>endDay){

                                }
                                else if(dateTagDay<=endDay){
                                    createScheduleBox(scheduleData[i], dateTags[j]);
                                }
                            }
                        }
                        else if(dateTagMonth<endMonth){
                            // 시작 날짜 비교
                            if(dateTagDay<startDay){
                                // 일정 시작 안함 
                            }
                            else if(dateTagDay=>startDay){
                                // 일정은 시작됨, 마지막 날 비교
                                createScheduleBox(scheduleData[i], dateTags[j]);
                            }
                        }
                    }	
                }
                else if(dateTagYear>endYeat){
                    // 존재할 수 없는 경우
                }	
            }
            else if(dateTagYear<startYear){
                // 일정 시작 안함
            }
        }
    }
}
더보기
function checkMonthScheduleFirst(){
    let scheduleBoxs = document.getElementsByClassName("scheduleBox");
    let scheduleNums = document.getElementsByClassName("scheduleNum");

    let scheduleTotal = [];

    for(let i = 0; i<scheduleNums.length; i++){
        let sn = parseInt(scheduleNums[i].value);//스케쥴 넘버의 값
        scheduleTotal.push(sn);
    }
    // 현재 페이지의 스케쥴 태그의 넘버를 가져옴 // 중복값은 생략해서 가져옴
    scheduleTotal = Array.from(new Set(scheduleTotal));

    for(let i = 0; i<scheduleTotal.length; i++){
        let boxArray = [];

        for(let j = 0; j <scheduleBoxs.length; j++){
            let sv = scheduleBoxs[j].getElementsByClassName("scheduleNum");

            if(sv.length==1){
                sv = sv[0].value;
            }

            if(scheduleTotal[i]==sv){
                boxArray.push(scheduleBoxs[j]);
            }
        }

        let flagSize = 0;
        let flagYoil;
        let flagDrawn = 0;
        let flagBefore = 0;

        for(let l = 0; l<boxArray.length; l++){
            // 해당 태그의 첫 요소의 데이터를 가져와서, 날짜를 파악> 요일 구해서 요일따라 길이 정해야함
            let dateTag = boxArray[l].parentElement.parentElement.getElementsByClassName("dateTag")[0];
            let dateTagYear = parseInt(dateTag.value.substring(0,4));
            let dateTagMonth = parseInt(dateTag.value.substring(4,6));
            let dateTagDay = parseInt(dateTag.value.substring(6,8));

            let dateTagYoil = getYoil(getThisDay(dateTagYear, dateTagMonth, dateTagDay, 0, 0));

            if(l==0||flagDrawn==0){

                if(dateTagYoil=="일"){
                    flagSize = 7;
                    flagDrawn = 7;
                    flagBefore = 0;
                }
                else if(dateTagYoil=="월"){
                    flagSize = 6;
                    flagDrawn = 6;
                    flagBefore = 1;
                }
                else if(dateTagYoil=="화"){
                    flagSize = 5;
                    flagDrawn = 5;
                    flagBefore = 2;
                }
                else if(dateTagYoil=="수"){
                    flagSize = 4;
                    flagDrawn = 4;
                    flagBefore = 3;
                }
                else if(dateTagYoil=="목"){
                    flagSize = 3;
                    flagDrawn = 3;
                    flagBefore = 4;
                }
                else if(dateTagYoil=="금"){
                    flagSize = 2;
                    flagDrawn = 2;
                    flagBefore = 5;
                }
                else if(dateTagYoil=="토"){
                    flagSize = 1;
                    flagDrawn = 1;
                    flagBefore = 6;
                }
                let grandfa = boxArray[l].parentNode.parentNode;
                let pregrandfa;
                // 새로 보강한 알고리즘
                for(let t = 0; t < flagBefore; t++){
                    pregrandfa = grandfa.previousSibling;
                    grandfa = pregrandfa;

                    let pregrandfabox = pregrandfa.getElementsByClassName("monthBoxBody")[0];

                    let boxx = document.createElement("div");
                    boxx.classList.add("cmpb0");

                    pregrandfabox.appendChild(boxx);
                }

                if(flagSize>boxArray.length-l){
                    // 사이즈칸 짜리 플래그 넣어주면 됨.
                    flagSize=boxArray.length-l;

                    boxArray[l].classList.add(checkMonthPlanBar(flagSize));
                    boxArray[l].classList.add("firstElementSchedule");
                    let temp1 = boxArray[l].getElementsByClassName("scheduleInfos")[0];
                    let temp2 = temp1.getElementsByClassName("scheduleTitle")[0].value;
                    let temp3 = temp1.getElementsByClassName("groupColor")[0].value;

                    c = document.createElement("span");
                    c.classList.add("scheduleGroupColor")
                    let thisColor = "background-color: "+temp3;
                    c.setAttribute("style", thisColor);
                    boxArray[l].appendChild(c);

                    c = document.createElement("span");
                    c.classList.add("scheduleTitleInSpan")
                    c.innerHTML = temp2;
                    boxArray[l].appendChild(c);
                }
                else{
                    // 사이즈 만큼 그리고 빈 수만큼 
                    boxArray[l].classList.add(checkMonthPlanBar(flagSize));
                    boxArray[l].classList.add("firstElementSchedule");
                    let temp1 = boxArray[l].getElementsByClassName("scheduleInfos")[0];
                    let temp2 = temp1.getElementsByClassName("scheduleTitle")[0].value;
                    let temp3 = temp1.getElementsByClassName("groupColor")[0].value;

                    c = document.createElement("span");
                    c.classList.add("scheduleGroupColor")
                    let thisColor = "background-color: "+temp3;
                    c.setAttribute("style", thisColor);
                    boxArray[l].appendChild(c);

                    c = document.createElement("span");
                    c.classList.add("scheduleTitleInSpan")
                    c.innerHTML = temp2;
                    boxArray[l].appendChild(c);
                }	
            }
            else{
                boxArray[l].classList.add("cmpbzero");
            }
            flagDrawn--;
        }
    }
}
더보기
function viewGroupForSchedule(){
    let clicked = event.target;
    let groupDiv = clicked.parentNode;
    let num = groupDiv.parentNode.getElementsByClassName("groupDataNum")[0].value;
    let flag = groupDiv.parentNode.getElementsByClassName("groupDataFlag")[0];

    if(flag.value=="true"){
        flag.setAttribute("value", "false"); // 안보이는 상태
        clicked.setAttribute("style", "background-color: #ff3409;");
        clicked.innerHTML="끄기";
    }
    else if(flag.value=="false"){
        flag.setAttribute("value", "true"); // 보이는 상태 
        clicked.removeAttribute("style");
        clicked.innerHTML="보기";
    }

    viewScheduleElementFlag();
}

// 스케줄 보이거나 감추기 작동
// 스케줄을 보일때와 안보일때를 실제로 동작하는 구분 
// 위의 펑션과 연결되어 사용함 
function viewScheduleElementFlag(){
    let selectForm = document.getElementsByClassName("selectForm")[0];
    let groupDiv = document.getElementsByClassName("groupElement");

    if(selectForm.value=="Y"){
        let yearformEls = document.getElementsByClassName("yearformEl");

        for(let i = 0; i < groupDiv.length; i++){

            let flag = groupDiv[i].getElementsByClassName("groupDataFlag")[0].value+"";
            let num = groupDiv[i].getElementsByClassName("groupDataNum")[0].value+"";;

            for(let l = 0; l <yearformEls.length; l++){
                let scHidden = yearformEls[l].getElementsByClassName("scHidden");

                for(let j = 0; j <scHidden.length; j++){
                    let scHiddenNum = scHidden[j].getElementsByClassName("groupNum")[0].value+"";

                    if(num==scHiddenNum){
                        if(flag=="true"){
                            scHidden[j].parentNode.classList.remove("hiddenElement");
                        }
                        else if(flag=="false"){
                            scHidden[j].parentNode.classList.add("hiddenElement");
                        }
                    }
                }
            }
        }
    }
    else if(selectForm.value=="M"){
        let schedules = document.getElementsByClassName("scheduleBox");

        for(let i = 0; i < groupDiv.length; i++){
            let flag = groupDiv[i].getElementsByClassName("groupDataFlag")[0].value+"";
            let num = groupDiv[i].getElementsByClassName("groupDataNum")[0].value+"";;
            for(let j = 0; j <schedules.length; j++){
                let scheduleNum = schedules[j].getElementsByClassName("groupNum")[0].value+"";

                if(num==scheduleNum){
                    if(flag=="true"){
                        schedules[j].classList.remove("hiddenElement");
                    }
                    else if(flag=="false"){
                        schedules[j].classList.add("hiddenElement");
                    }
                }
            }
        }
    }
    else if(selectForm.value=="D"){
        let daySchedule = document.getElementsByClassName("dayScheduleBox");
        let alldaySchedule = document.getElementsByClassName("alldayScheduleBox");

        for(let i = 0; i < groupDiv.length; i++){
            let flag = groupDiv[i].getElementsByClassName("groupDataFlag")[0].value+"";
            let num = groupDiv[i].getElementsByClassName("groupDataNum")[0].value+"";;
            for(let j = 0; j <daySchedule.length; j++){

                let scheduleNum = daySchedule[j].getElementsByClassName("groupNum")[0].value+"";

                if(num==scheduleNum){
                    if(flag=="true"){
                        daySchedule[j].classList.remove("hiddenElement");
                    }
                    else if(flag=="false"){
                        daySchedule[j].classList.add("hiddenElement");
                    }
                }
            }

            for(let k = 0; k <alldaySchedule.length; k++){

                scheduleNum = alldaySchedule[k].getElementsByClassName("groupNum")[0].value+"";

                if(num==scheduleNum){
                    if(flag=="true"){
                        alldaySchedule[k].classList.remove("hiddenElement");
                    }
                    else if(flag=="false"){
                        alldaySchedule[k].classList.add("hiddenElement");
                    }
                }
            }
        }
    }
}
더보기
function checkFirstElement(){
    let scheduleBox = document.getElementsByClassName("scheduleBox ");
    let temp = 0; 

    for(let i = 0; i < scheduleBox.length; i++){
        if(scheduleBox[i].classList.contains("firstElementSchedule")){
            let p = scheduleBox[i].parentNode;
            let cmpb0 = p.getElementsByClassName("cmpb0");
            let fr = p.getElementsByClassName("firstElementSchedule");

            let height = 22;

            for(let j = 0; j < fr.length; j++){
                let getAtt = fr[j].getAttribute("style")+";";
                let num = cmpb0.length+j;

                let hg = "margin-top:"+(height*num)+"px;";

                fr[j].setAttribute("style", getAtt+hg);

            }
        }
        let pnum = scheduleBox[i].parentNode.childElementCount;
        if(temp<pnum){
            temp = pnum;
        }
    }
    let monthBoxs = document.getElementsByClassName("monthBox");

    for(let i = 0; i < monthBoxs.length; i++){

        let hg = temp*22;
        hg = hg+22;
        monthBoxs[i].setAttribute("style", "height:"+hg+"px;");
    }	
}

 

 

5. 개선점

스케줄의 데이터 처리는 복잡하게 진행된다. 

계정의 데이터를 기반으로 그룹 정보를 조회하고, 이를 기반으로 스케줄을 조회한다.

조회한 데이터를 모양에 맞게 표현해주는 것 또한 필요하다. 

 

복합적이고 다양한 데이터를 여러 차례 정제하면서 모양을 구현하고 있다. 

 

내가 파악한 가장 큰 개선점은 데이터 정제 및 정렬에 있어서, 별도의 정렬 알고리즘을 사용하여 이를 적용해야 한다는 점이다. 

 

위와 같은 경우, 특정 영역은 1줄로 다 표현이 가능하다.

예를 들어 막대가 차지하는 면적이 겹치지 않으며 2칸을 차지한다면, 5칸을 차지하는 막대와 1줄에서 표시할 수 있다. 

 

이를 적용하기 위해서는 다음과 같은 개선 방법을 적용해볼 수 있다.

 

  • 2중 배열로, 현재 막대의 데이터를 체크하면서 재정렬한다. 
  • 데이터를 가져올 때, 정렬을 위해 순차적으로 데이터를 정렬하고 계산하여 가져온다. 

 

다만 이를 적용하기 위해서는 같은 블럭 단위를 이동시키도록 스케줄 넘버를 검증하고 이동시켜야 한다. 

이동은 막대 너비가 큰 경우 부터 시작하여 작은 단위로 진행해야 한다. 

 

개발 기간에 제한이 있어 이를 완벽하게 구현할 시간이 부족했지만, 위의 방법으로 진행하면 해결을 시도할 수 있다.