티스토리 뷰
[js] php화면에 자바스크립트 활용해서 스케줄표 그려주기, 실무에서 사용한 코드
Coding Life 2021. 12. 18. 21:24작업스케줄을 만들때 중요한 것은 누적된 데이터를 시각화 하는 것인데, 누적데이터 만드는 것이 처음이라 많이 헤매면서 코딩했습니다.
쉽지 않은 작업이었던 기억이 오래 많을 것 같네요.
<?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> <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 등으로 제작한 것입니다.
서버프로그램과 클라이언트 프로그램의 호환성때문에 코딩하기가 쉽지 않지만, 더 좋은 방법을 늘 찾아볼게요.
즐거운 주말 되시길...
'IT tech Coding > javascript' 카테고리의 다른 글
toast UI Grid 자료를 서버에 저장하는 방법(save grid 함수제작) (0) | 2021.12.23 |
---|---|
자바스크립트 초를 시간형식으로 바꿔주는 함수 (0) | 2021.12.18 |
jexcel에서 toast UI grid로 웹사이트 변경작업하기 (0) | 2021.12.12 |
[자바스크립트] 간단히 CSV파일 다운로드 만들어 보기 (0) | 2021.11.28 |
자바스크립트로 줌인 줌아웃 만들어 보자, ZOOM IN ZOOM OUT 어렵지 않아요~~ (0) | 2020.04.13 |
- Total
- Today
- Yesterday
- #소프트웨어배포
- 티스토리챌린지
- #파이썬패키징
- 코딩튜토리얼
- #파이썬인스톨러
- coalesce는 한국어로 "코얼레스크" 또는 "코얼리스"
- 파이썬코드줄바꿈방법
- 엑셀보호
- sql문장 날짜계산
- 효율적코딩방법
- Bootstrap 5
- 오블완
- 뫄프로그래밍
- General error: 2031
- 엑셀입력보호
- #독립실행파일
- #cx_Freeze
- #NSIS
- 스크립트작성기초
- #InnoSetup
- 2분후종료오토핫키
- 프로그래머생활
- #InstallForge
- 오토핫키가이드
- 코딩효율성
- chatGPT3.5파이썬버전
- #프로그램설치
- 구글드라이브API
- 엑셀셀보호
- 테크에능한여성
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |