티스토리 뷰

반응형

작업스케줄을 만들때 중요한 것은 누적된 데이터를 시각화 하는 것인데, 누적데이터 만드는 것이 처음이라 많이 헤매면서 코딩했습니다.

쉽지 않은 작업이었던 기억이 오래 많을 것 같네요.

<?php session_start(); 
include 'common.php';  // php 함수들 모음

header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header ("Pragma: no-cache"); // HTTP/1.0
header("Expires: 0"); // rfc2616 - Section 14.21   
// header("Content-Type: application/json");//json을 사용하기 위해 필요한 구문
ini_set('display_errors','0');  // 화면에 warning 없애기
//header("Refresh:0");  // reload refresh  

$user_name= $_SESSION["name"];
$user_id= $_SESSION["userid"];
isset($_REQUEST["SelectWork"])  ? $SelectWork=$_REQUEST["SelectWork"] :   $SelectWork=''; 
isset($_REQUEST["searchOpt"])  ? $searchOpt=$_REQUEST["searchOpt"] :   $searchOpt=''; 
?>

<!DOCTYPE html>
<meta charset="UTF-8">
<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
 
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css">

<link rel="stylesheet" href="../css/style.css"/>  
<link rel="stylesheet" href="./css/style.css"/>
<!-- JavaScript Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/460/fabric.js"> </script>

<body>
<title> 작업 스케줄러(SCHEDULER) </title>
<style>
   @import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css");
   
* {
    margin: 0;
    padding: 0
}

.custom_calendar_table td {
    text-align: center;
}

.custom_calendar_table thead.cal_date th {
    font-size: 2.5rem;
	text-align: center;
	height: 40px;
	margin-bottom: 15px;	
}

.custom_calendar_table thead.cal_date th button {
    font-size: 2.5rem;
    background: none;
    border: none;
}

.custom_calendar_table thead.cal_week th {
    background-color: #A0A0A0;
	font-size: 2.0rem;
	height: 60px;
	margin-bottom: 15px;
    color: #fff;
	text-align: center;
}

.custom_calendar_table tbody td {
   /* cursor: pointer; */
}

.custom_calendar_table tbody td:nth-child(1) {
    color: red;
	height: 100px;	
}

.custom_calendar_table tbody td:nth-child(7) {
    color: #288CFF;
	height: 700px;	
}

.custom_calendar_table tbody td.select_day {
  /*  background-color: #288CFF;
    color: #fff; */
}   
	
</style>
	<header class ="d-flex fex-column align-items-center flex-md-row p-1 bg-secondary" >
		<h1 class="h4 my-0 me-md-auto">  <img src="./img/eunsung_logo.jpg" alt="은성레이져">	은성레이져 작업 스케줄러(SCHEDULER) </h1>
		<div class="d-flex align-items-center">	 
		<?php include "./lib/top_menu.php"; ?>
			<div class="flex-grow-1 ms-3">
					 <?php
						if(!isset($_SESSION["userid"]))
						{
					?>
							  <a href="../login/login_form.php">로그인</a> | <a href="../member/insertForm.php">회원가입</a> 
							  
					<?php
						}
						else
						 {
					?>
						<?=$_SESSION["name"]?> (level:<?=$_SESSION["level"]?>) | 
						   <!-- <a href="write_state.php">가입</a>  -->
							<a href="../login/logout.php">로그아웃</a> | <a href="../member/updateForm.php?id=<?=$_SESSION["userid"]?>">정보수정</a>
							
					<?php
						 }
					?>	
		   </div>	  
		</div>
	</header>


	
</head>

	<br>
 <form name="Form">
    <input type=hidden id="fromdate" name="fromdate" value="2021-12-18">
    <input type=hidden id="todate" name="todate" value="2021-12-18">
    <input type=hidden id="weekend" name="weekend" value="">
</form>



	<button type="button" class="button btn btn-secondary" onclick="week_calandar(-1)"> < </button>
	<button type="button" class="button btn btn-secondary" onclick="set_day()" > Today </button>
	<button type="button" class="button btn btn-secondary" onclick="week_calandar(1)"> > </button>  &nbsp;&nbsp; <div id="calandarTitle"></div> 
  <div id=calwrap style="float:left;width:100%;height:900px;"> 
    <div id="calwrap col1" style="float:left;width:110px;height:900px;margin-left:10px;"> 

	  <canvas id="ruler06" style="float:left;width:100px;height: 185px;border:1px;"> </canvas>
	  <canvas id="ruler0" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler1" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler2" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler3" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler4" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler5" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler6" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler8" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler7" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler9" style="float:left;width:100px;height: 30px;border:1px;"> </canvas>
	  <canvas id="ruler10" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler11" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler12" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler13" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler14" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler15" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler16" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler17" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler18" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler19" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	  <canvas id="ruler20" style="float:left;width:100px;height:30px;border:1px;"> </canvas>
	</div>
    <div id="calwrap col2" style="float:left;width:1750px;height:900px;"> 	
	 <div id="calandar"></div> 
	 </div>

</div>
		  
<script> 

let dayArray = new Array(); 

var nowDate = new Date();
function calendarMaker(target, date) {
    if (date == null || date == undefined) {
        date = new Date();
    }
    nowDate = date;
    if ($(target).length > 0) {
        var year = nowDate.getFullYear();
        var month = nowDate.getMonth() + 1;
        var date = nowDate.getDate();
        var day = nowDate.getDay();
        $(target).empty().append(assembly(year, month, date));
    } else {
        console.error("custom_calendar Target is empty!!!");
        return;
    }

    var thisMonth = new Date(nowDate.getFullYear(), nowDate.getMonth(), 1);
    var thisLastDay = new Date(nowDate.getFullYear(), nowDate.getMonth() + 1, 0);

    var tag = "<tr>";
    var cnt = 0;
    // 주간 창 만들어주기
    for (i = 0; i < 7 ; i++) {
        tag += "<td> <canvas id='myChart" + (i+1) + "' width='245' height='700'></canvas> </td>";
        cnt++;
    }
    // for (i = 0; i < thisMonth.getDay(); i++) {
        // tag += "<td></td>";
        // cnt++;
    // }

    // //날짜 채우기
    // for (i = 1; i <= thisLastDay.getDate(); i++) {
        // if (cnt % 7 == 0) { tag += "<tr>"; }

        // tag += "<td>" + i + "</td>";
        // cnt++;
        // if (cnt % 7 == 0) {
            // tag += "</tr>";
        // }
    // }
    $(target).find("#custom_set_date").append(tag);
    calMoveEvtFn();

    function assembly(year, month, date) {
        var calendar_html_code =
            "<table class='custom_calendar_table'>" +
            "<colgroup>" +
            "<col style='width:250px;'/>" +
            "<col style='width:250px;'/>" +
            "<col style='width:250px;'/>" +
            "<col style='width:250px;'/>" +
            "<col style='width:250px;'/>" +
            "<col style='width:250px;'/>" +
            "<col style='width:250px;'/>" +
            "</colgroup>" +
            "<thead class='cal_date'>" +
            "<th class='colTitle' colspan='7'> </th>" +           
            "</thead>" +
            "<thead  class='cal_week'>" +
            "<th>" + dayArray[0] + "(일)</th>" +
            "<th>" + dayArray[1] + "(월)</th>" +
            "<th>" + dayArray[2] + "(화)</th>" +
            "<th>" + dayArray[3] + "(수)</th>" +
            "<th>" + dayArray[4] + "(목)</th>" +
            "<th>" + dayArray[5] + "(금)</th>" +
            "<th>" + dayArray[6] + "(토)</th>" +			 
            "</thead>" +
            "<tbody id='custom_set_date'>" +
            "</tbody>" +
            "</table>";
        return calendar_html_code;
    }

    function calMoveEvtFn() {
        //전달 클릭
        $(".custom_calendar_table").on("click", ".prev", function () {
            nowDate = new Date(nowDate.getFullYear(), nowDate.getMonth() - 1, nowDate.getDate());
            calendarMaker($(target), nowDate);
        });
        //다음날 클릭
        $(".custom_calendar_table").on("click", ".next", function () {
            nowDate = new Date(nowDate.getFullYear(), nowDate.getMonth() + 1, nowDate.getDate());
            calendarMaker($(target), nowDate);
        });
        //일자 선택 클릭
        $(".custom_calendar_table").on("click", "td", function () {
            $(".custom_calendar_table .select_day").removeClass("select_day");
            $(this).removeClass("select_day").addClass("select_day");
        });
    }
}

function week_calandar(week) {
	day.setDate(day.getDate()+week*7);
	var title = day.getFullYear() + "-" + (day.getMonth()+1) + "-" + day.getDate();
	$('#fromdate').val(title);	
	var data = ""
	for(var i=0 ; i<7 ; i++) {
		data += day.getDate() + "|";
		dayArray[i] = day.getDate();
        var fromdate = day.getFullYear() + "-" + (day.getMonth()+1) + "-" + dayArray[i];		
		$('#fromdate').val(fromdate);
		$('#todate').val(fromdate);
		$('#weekend').val(i);          // 요일에 대한 정보를 함께 넘겨준다.
        displayResult();    // php에 전송해서 결과값 받기			
		day.setDate(day.getDate()+1);
	}
	const tmp = day.getFullYear() + "-" + (day.getMonth()+1)+ "-" + (day.getDate()-1);
	title += " ~ " + tmp;	
	$('#todate').val(tmp);	
	day.setDate(day.getDate()-7);
	// document.getElementById("calandarTitle").innerHTML = title + "<br />" + data;
	calendarMaker($("#calandar"), new Date());
	$('.colTitle').text(title);	

}

function set_day() {
	day = new Date();
	day.setDate(day.getDate()-day.getDay());
	week_calandar(0);
}
	

$(document).ready(function(){	

	//no1 버튼을 클릭 했을떄 이벤트
	displayResult = function(){
	    $.ajax({
			url: "stackedDate.php",
    	  	type: "post",		
   			data: $("Form").serialize(),
   			dataType:"json",
		}).done(function(data){
		//	console.log(data);
		const weekend = data["weekend"];
			//json을 통해 가져온 데이타를 input_data tag에 넣어준다.
		//  console.log(data["laser3030_arr"]);
		//  console.log(data["laser1030_arr"]);
		//	const target = Object.values(data);  // 배열화 작업
		//	console.log(target);		
        //	console.log(JSON.stringify(data));
			var html = "";
				html += "<tr>";
				html += "<td>"+ data.fromdate +"</td>";
				html += "<td>"+ data.todate +"</td>";
				
			// for(value in data){
				// console.log(value);
			// }	
			
			// data["laser3030_arr"].forEach(function(v){          // object로 넘어온 데이터를 배열형태로 볼 수 있는 방법임.
			  
			    // //  console.log(v);
				// drawGraph('3030',v);				
				
			// })
			
			drawGraph('3030',weekend ,data["laser3030_arr"],data["laser1030_arr"]);	// 배열로 전달함.			
		//	drawGraph('3030',weekend ,...data["laser3030_desarr"]);	// 배열로 전달함.			
		//	drawGraph('1030',weekend ,...data["laser1030_arr"]);	// 배열로 전달함.			
		//	drawGraph('1030',weekend ,...data["laser1030_desarr"]);	// 배열로 전달함.			
			
			// for(key in data){
				// console.log(data[key]); //-> 키값, 모든 value 출력 
				
				// //console.log(key); -> key값들만 출력 
			// }			
				
				html += "</tr>";

			$("#input_data").html(html);
			

 		}); 
          
	}

	//tbody 안에 있는 내용 지우기
	$('#no2').click(function(){
	    $("#input_data").empty();
	});

set_day();
	
var day = new Date();
day.setDate(day.getDate()-day.getDay());	
   
	var ctx1 = document.getElementById('myChart1');
	var ctx2 = document.getElementById('myChart2');
	var ctx3 = document.getElementById('myChart3');
	var ctx4 = document.getElementById('myChart4');
	var ctx5 = document.getElementById('myChart5');
	var ctx6 = document.getElementById('myChart6');
	var ctx7 = document.getElementById('myChart7');

// 눈금선 그리기
	drawRuler('ruler0','20:30');
	drawRuler('ruler1','20:00');
	drawRuler('ruler2','19:30');
	drawRuler('ruler3','19:00');
	drawRuler('ruler4','18:30');
	drawRuler('ruler5','17:30');
	drawRuler('ruler6','17:00');
	drawRuler('ruler7','16:30');
	drawRuler('ruler8','16:00');
	drawRuler('ruler9','15:30');
	drawRuler('ruler10','15:00');
	drawRuler('ruler11','14:30');
	drawRuler('ruler12','14:00');
	drawRuler('ruler13','13:30');
	drawRuler('ruler14','12:00');
	drawRuler('ruler15','11:30');
	drawRuler('ruler16','10:30');
	drawRuler('ruler17','10:00');
	drawRuler('ruler18','09:30');
	drawRuler('ruler19','09:00');
	drawRuler('ruler20','08:30');

	
function drawRuler(canvas,comment) { 	
	const canvasRuler = document.getElementById(canvas); 
	const ctx = canvasRuler.getContext("2d"); // 3. 새선 그리기 설정 
	ctx.beginPath();        // 4. 출발점 지정 
	ctx.font = '85px 굴림';
	ctx.strokeStyle = '#000';
	let gapNum;
   for(i=0;i < 1; i++) {
	gapNum = i * 50;
	ctx.moveTo(10, 125-gapNum);    // 5. 도착점 지정 
	ctx.lineTo(300, 125-gapNum);     // 6. 선 그리기 
	ctx.lineWidth = 1;
	ctx.stroke(); 
	ctx.fillText(comment, 5, 125-gapNum);   // b2치수 출력     
   }
}

});


function drawGraph(item, weekend, arr1, arr2) {
	// laser3030 그려주기
        var canvas;
		const RATIO = 180 * 56 / 180;  // 30분 간격이 56px로 계산하면 1px당 시간(초)는 
		weekend++;
		console.log(arr1);
		console.log(arr2);

		canvas = new fabric.Canvas('myChart' + weekend);		

		var Line = new fabric.Line([0, 350, 250, 350], 
		      {  left: 0, top: 250, stroke: 'red' });
        canvas.add(Line);					          
		
		let stackedH= 0;
		let bottomPos = 0;
		let graphGap = 1;
	    for(var i=0; i< arr1.length; i++) {	
		 graphH = Math.floor(arr1[i] / RATIO) ;
		 stackedH += graphH;
		var Rect = new fabric.Rect({
		 left: 0, top: 700 - bottomPos , width: 120, height: graphH *(-1) , fill: '#90EE90',
			});
		  canvas.add(Rect);		
		  bottomPos += (graphH + graphGap); // 막대그래프 중간간격 띄워줌.
		}		
		
		var text = new fabric.Text('3030', { left: 10, top: 650 , fontSize: 40} );
        canvas.add(text);					  
	  	  					          
	// 1030 그려주기	
		stackedH= 0;
		bottomPos = 0;
		graphGap = 1;
	    for(i=0; i< arr2.length; i++) {	
		 graphH = Math.floor(arr2[i] / RATIO) ;
		 stackedH += graphH;
		 Rect = new fabric.Rect({
		 left: 125, top: 700 - bottomPos , width: 120, height: graphH *(-1) , fill: '#00994C',
			});
		  canvas.add(Rect);		
		  bottomPos += (graphH + graphGap); // 막대그래프 중간간격 띄워줌.
		}		
		
		text = new fabric.Text('1030', { left: 135, top: 650 , fontSize: 40} );
        canvas.add(text);		
}
					 
function getToday(){   // 2021-01-28 형태리턴
    var now = new Date();
    var year = now.getFullYear();
    var month = now.getMonth() + 1;    //1월이 0으로 되기때문에 +1을 함.
    var date = now.getDate();

    month = month >=10 ? month : "0" + month;
    date  = date  >= 10 ? date : "0" + date;
     // ""을 빼면 year + month (숫자+숫자) 됨.. ex) 2018 + 12 = 2030이 리턴됨.

    //console.log(""+year + month + date);
    return today = ""+year + "-" + month + "-" + date; 
}

function getCurrentTime(){   // 01:00:00 형태리턴  현재시간 리턴
	var today = new Date();   

	var hours = ('0' + today.getHours()).slice(-2); 
	var minutes = ('0' + today.getMinutes()).slice(-2);
	var seconds = ('0' + today.getSeconds()).slice(-2); 

	var timeString = hours + ':' + minutes  + ':' + seconds;
	return timeString;
	console.log(timeString);
}

  </script>
    </div>
  </div>	 
</section>

</body>

</html>

작업시간을 누적해서 시각적으로 보여주는 프로그램을 목표로 일주일정도 연습도 하고, 기존 정보를 활용해서 작성을 해봤지만, chartjs, toast UI calender 등등을 활요하는데도 많은 지식이 필요한 것 같습니다.

그리하여, fabicJS를 이용하고, 기본 canvas를 이용해서 어느정도 구현이 된 것 같네요.

아직 만족할 수준에는 한참 모자라지만, 그래도 처음에는 너무 막막했는데, week calender를 구현하고, 그 후 하나씩 살을 붙여 만들었네요.

ajax를 사용해서 비동기적으로 php DB의 자료를 가져와서 화면에 뿌려주는 것까지 구현하니, 마음이 한결 가벼워졌습니다.

Laser 가공시간을 누적해서 작업의 정체구간을 찾기위한 목적으로 처음시작해서 만들어가는 과정인데, 그 과정의 코드를 남겨볼까 합니다.

강제로 눈금선을 그려주고, 완전 힘든 코딩을 했지만, 그래도 뭔가를 구현했다는 뿌듯함은 있군요.

 

ajax에 사용한 stackedDate.php 코드

<?php
header("Content-Type: application/json");  //json을 사용하기 위해 필요한 구문

isset($_REQUEST["fromdate"])  ? $fromdate=$_REQUEST["fromdate"] :   $fromdate=''; 
isset($_REQUEST["todate"])  ? $todate=$_REQUEST["todate"] :   $todate=''; 
isset($_REQUEST["weekend"])  ? $weekend=$_REQUEST["weekend"] :   $weekend=''; 

require_once("../lib/mydb.php");
$pdo = db_connect();	

$common="   where TIME_DATE between date('$fromdate') and date('$todate') order by TIME_DATE ";
$b= $common . " desc, num desc ";    //내림차순 전체   

$sql="select * from (각자 자신의 DB주소)  " . $b; 	
 
$laser3030_arr=array(); 
$laser3030_desarr=array(); 
$laser1030_arr= array();
$laser1030_desarr= array();

	 try{  
// 레코드 전체 sql 설정
   $stmh = $pdo->query($sql);            // 검색조건에 맞는글 stmh
   $i= 0;  // 3030 누적
   $j= 0;  // 1010 누적
   
   while($row = $stmh->fetch(PDO::FETCH_ASSOC)) {

            $num=$row["num"];
			  
			$laser1030 = $row["laser1030"];
		    $laser3030 = $row["laser3030"];	
			$PROD_DES = $row["PROD_DES"];
		    $SIZE_DES = $row["SIZE_DES"];				
            if((int)$laser3030>0) {
	              $laser3030_arr[$i]=$laser3030_arr[$i] + (int)$laser3030;		
	              $laser3030_desarr[$i]=$PROD_DES . '[' . $SIZE_DES . ']';     // 품목명 + 규격형태 저장
			      $i++; 	           	  
		    	}
            if((int)$laser1030>0) {				
	              $laser1030_arr[$j]=$laser1030_arr[$j] + (int)$laser1030;		
	              $laser1030_desarr[$j]=$PROD_DES . '[' . $SIZE_DES . ']';
				  $j++;
		     	}	         
			}		 
   } catch (PDOException $Exception) {
    print "오류: ".$Exception->getMessage();
}  

//각각의 정보를 하나의 배열 변수에 넣어준다.
$data = array(
	// "fromdate"=> $fromdate,
	// "todate"=> $todate,
	"weekend"=> $weekend,
	"laser3030_arr" =>         $laser3030_arr,
	"laser3030_desarr" =>      $laser3030_desarr,
	"laser1030_arr" =>         $laser1030_arr,
	"laser1030_desarr" =>      $laser1030_desarr
);
   
//json 출력
echo(json_encode($data, JSON_UNESCAPED_UNICODE));

?>

 

실행하니, 잘 이렇게 그래프가 잘 나옵니다. 레이져와 다른 공정들도 만들어서 이제는 혼합으로 하는 것에 도전해 볼 생각입니다.

PHP, javascript(Jquery, JSON), MYSQL 등으로 제작한 것입니다.

서버프로그램과 클라이언트 프로그램의 호환성때문에 코딩하기가 쉽지 않지만, 더 좋은 방법을 늘 찾아볼게요.

즐거운 주말 되시길...

 

반응형
댓글