28일 볼튕기기 이어서 작성
기존에는 클릭할 때마다 이동속도가 증가한다 -> 클릭해도 속도 변화가 없게 변경하기
// script부분↓↓
/*
clearTimeout(timerId);
이렇게 하면 되는 것 처럼 보이지만 사용자는 속을수 있다(자원을 만들었다 지웠다 반복) -> 좋은 아이디어가 아니다
timerId = setTimeout(fMove,30); // 재귀호출
*/
}
//fMove();
// script 위쪽에 작성 ↓↓
let isStart = false; // 초기값 아직 시작 안된상태
const fStart = function(){
if(!isStart){ // 처음 시작시에만 호출하므로 아무리 클릭해도 더이상 빨라지지 않는다
fMove();
isStart = true;
}
}
// body부분 작성 ↓↓
<div id="myBall"></div>
<button onclick="fStart()">시작</button>
stop버튼 만들기
// body부분↓↓
<button onclick="fStop()">끝</button>
// script부분↓↓
const fStop = function(){
if(timerId){ // 타이머가 있을때만
clearTimeout(timerId);
isStart=false;
}
}
프록시 서버 , 리버스 프록시 서버(Reverse Proxy Server), Reverse Proxy Nginx(역방향프록시)
데이터베이스를 사용하는 시스템에서 통계를 안하면(안내면) 안한것과 똑같다
통계 : 데이터 취합, 조합 -> 정보 , 흐름 , 변화
d3.js
chart.js -> getting started 샘플소스 가져오기 -> body부분에 추가
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- chart.js는 아주 잘 만들어져서 , 한번만 확인하면 그 사용법을 잊어버리기가 더 어려움 -->
<!-- 부모크기 조정시 차트 크기 조정가능 -->
<div style="width: 600px;">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// const ctx = document.getElementById('myChart');
// -> 아래처럼 변경
const ctx = document.querySelector('#myChart');
// chart.js가 잘만들어진 이유는 생성자 리턴값에 옵션내용이 거의 다 들어있어서
// 직관적으로 값을 조정할 수 있음
const myChart = new Chart(ctx, {
type: 'bar',/* bar , line , pie , doughnut , radar (차트종류) */
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets:
[
{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '인호 변화 추이', // null?
data: [100, 190, 30, 50, 20, 0],
borderWidth: 1
}
]
},
options: { // 검색으로 해결
scales: {
y: {
beginAtZero: true
}
}
}
});
// null
/*
let newDataset = {
label: '인호 변화 추이', // null?
data: [100, 190, 30, 50, 20, 3],
borderWidth: 1
};
myChart.data.datasets.push(newDataset);
*/
// alert((myChart.data.datasets[0].data[1]));
// myChart.data.datasets[0].data[1] = 190;
myChart.update();
</script>
</body>
</html>
cdnjs.com -> 검색
chart.js 가 잘만들어진 이유?
chart.js에서 기억해야할 메소드 1개 -> update() -> 값을 변경했을 경우 다시 그려야하기 때문에(re-rendering)
버튼을 넣어보자 , 바디부분에 버튼 추가
<button onclick="fRandom()">값 변화</button>
<!-- script부분에 아래 추가 -->
const fRandom = function(){
let ranArr = [];
for(let i = 1; i <= 6 ; i++){
let ranVal = Math.round(Math.random()*40) + 60; // 60 ~ 100까지
ranArr.push(ranVal);
}
myChart.data.labels = ["본인" , "나" , "자기자신" , "로제","제니","있지","메롱"] // 라벨을 변경하고 싶으면??
myChart.data.datasets[1].type = "line"; // 이런식으로 각 데이터마다 타입을 다르게 지정 가능, line과 bar만 mix가능하다
myChart.data.datasets[1].data = ranArr;
myChart.update();
setTimeout(fRandom , 1000);
}
mixed도 가능하다(같이 사용가능한 차트를 동시에 보여준다?) -> line과 bar만 mixed 가능
가로축과 세로축을 바꾸려면? option에 indexAxis : 'y' 추가 -> 수평차트가 된다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<button onclick="fRandom()">값 변화</button>
<!-- chart.js는 아주 잘 만들어져서 , 한번만 확인하면 그 사용법을 잊어버리기가 더 어려움 -->
<!-- 부모크기 조정시 차트 크기 조정가능 -->
<div style="width: 600px;">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const fRandom = function(){
let ranArr = [];
let ranArr1 = [];
for(let i = 1; i <= 7 ; i++){
let ranVal = Math.round(Math.random()*40) + 60; // 60 ~ 100까지
let ranVal1 = Math.round(Math.random()*40) + 60; // 60 ~ 100까지
ranArr.push(ranVal);
ranArr1.push(ranVal1);
}
myChart.data.labels = ["본인" , "나" , "자기자신" , "로제","제니","있지","메롱"] // 라벨을 변경하고 싶으면??
myChart.data.datasets[1].type = "line"; // 이런식으로 각 데이터마다 타입을 다르게 지정 가능, line과 bar만 mix가능하다
myChart.data.datasets[1].data = ranArr;
myChart.data.datasets[0].data = ranArr1;
myChart.update();
setTimeout(fRandom , 1000);
}
// const ctx = document.getElementById('myChart');
// -> 아래처럼 변경
const ctx = document.querySelector('#myChart');
// chart.js가 잘만들어진 이유는 생성자 리턴값에 옵션내용이 거의 다 들어있어서
// 직관적으로 값을 조정할 수 있음
const myChart = new Chart(ctx, {
type: 'bar',/* bar , line , pie , doughnut , radar (차트종류) */
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets:
[
{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '인호 변화 추이', // null? , 이런식으로 추가도 가능
data: [100, 190, 30, 50, 20, 0],
borderWidth: 1
}
]
},
options: { // 검색으로 해결
indexAxis : 'y' ,
scales: {
y: {
beginAtZero: true
}
}
}
});
// null
/*
let newDataset = {
label: '인호 변화 추이', // null?
data: [100, 190, 30, 50, 20, 3],
borderWidth: 1
};
myChart.data.datasets.push(newDataset);
*/
// alert((myChart.data.datasets[0].data[1]));
// myChart.data.datasets[0].data[1] = 190;
myChart.update();
</script>
</body>
</html>
차트를 보여주게 된다면 차트의 의미까지 어느정도는 설명하고 넘어가면 좋다 (차트가 아니더라도 통계가 추가 된다면)
aggridjs.html 생성 -> 아래 샘플코드 추가(샘 블로그)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ag-Grid 시작 예제</title>
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
</head>
<body>
<h1>지금은 뉴진스 시대</h1>
<!-- 테마는 -->
<div id="myGrid" style="height: 250px; width:600px" class="ag-theme-quartz-dark"></div>
<script>
// 샘플 ROW 데이타 정의, DB Select의 1줄 Row들의 모임 list가 될거시당
const rowData = [
{ name: "민지", birth: "2004-05-07", nationality: "대한민국" },
{ name: "하니", birth: "2004-10-06", nationality: "호주|베트남" },
{ name: "다니엘", birth: "2005-04-11", nationality: "호주|한국" },
{ name: "해린", birth: "2006-05-15", nationality: "대한민국" },
{ name: "혜인", birth: "2008-04-21", nationality: "대한민국" }
];
// 통합 설정 객체, 아주 많은 속성들이 제공됨(일단 몇개만)
const gridOptions = {
rowData: rowData,
columnDefs: [ // 컬럼 정의
{ field: "name", headerName: "이름" },
{ field: "birth", headerName: "생일" },
{ field: "nationality", headerName: "국적" }
],
autoSizeStrategy: { // 자동사이즈정책
type: 'fitGridWidth', // 그리드넓이기준으로
defaultMinWidth: 150 // 컬럼 최소사이즈
},
rowHeight: 45 // row 높이지정
};
const gridDiv = document.querySelector('#myGrid');
// new agGrid.Grid(gridDiv, gridOptions); // deprecated
const gridApi = agGrid.createGrid(gridDiv, gridOptions);
</script>
</body>
</html>
객체지향데이터 스타일? , JSON?
테이블 -> rowData
정렬기능 : default
컬럼에 fiter : true 작성시 아래처럼 컬럼별로 해당 하는 검색기능 사용 가능(날짜면 날짜)
컬럼이 많아지면 직접 추가하기 불편하기 때문에 default Colum을 제공한다 -> 여기에 컬럼 추가하면 된다
defaultColDef: {
flex: 1, // 자동으로 같은 사이즈롱
filter: true,
resizable: true,
minWidth: 100,
headerClass: "centered"
},
dummyData.json 생성
[
{"name": "태한경", "alias": "숨겨진 고민", "strong": "다 이해됨", "weak": "근거가 없음"},
{"name": "공석규", "alias": "보면 다 이해", "strong": "담배피며 여유찾기", "weak": "찾을 여유가 없음"},
{"name": "노해건", "alias": "수학의 달인", "strong": "수학잘함", "weak": "산수못함"},
{"name": "뢰슬우", "alias": "허리 사선", "strong": "눈에 안띔", "weak": "존재가 안보임"},
{"name": "태래은", "alias": "일단 직진", "strong": "의외로 귀여움", "weak": "외모는 전혀 안 귀여움"},
{"name": "옥화정", "alias": "경로당 느낌?", "strong": "나이로 대우받기", "weak": "신체나이는?"},
{"name": "도중희", "alias": "외모는 진지", "strong": "눈빛은 남자", "weak": "말투는 여성여성"},
{"name": "구산아", "alias": "알람 그게 뭐얌", "strong": "계속 잠", "weak": "깨워도 잠"},
{"name": "좌하주", "alias": "부끄부끄 초딩", "strong": "챙겨주고 싶음", "weak": "맛집을 모름"},
{"name": "나승회", "alias": "나름욜씨미 ", "strong": "친한척하기", "weak": "안 친하고 픔"},
{"name": "은진온", "alias": "멋짱이", "strong": "파란차색깔", "weak": "본인은 안 푸름"},
{"name": "창승해", "alias": "깨달은자", "strong": "남의 실수 잘 찾기", "weak": "본인 실수는 못 찾음"},
{"name": "곡루이스", "alias": "배탈", "strong": "넘 열심", "weak": "취미 없음"},
{"name": "상현덕", "alias": "오마이걸", "strong": "유아 좋아함", "weak": "본인 나이는 어쩔"},
{"name": "교근찬", "alias": "술쎄보임", "strong": "좋은마우스", "weak": "힘없음"},
{"name": "연건한", "alias": "그저 웃지요", "strong": "답변은 웃음으로", "weak": "입이 할일이 없음"},
{"name": "홍길동", "alias": "전공자", "strong": "서류상 전공자", "weak": "서류빼면 비전공자"},
{"name": "김방구", "alias": "엄마", "strong": "노력 산더미", "weak": "결과는 티끌"},
{"name": "김채현", "alias": "비밀의 숲", "strong": "잘 감춤", "weak": "보여주면서 감춤"}
]
aggridTest.html 생성후 아래 붙여넣기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ag-Grid Basic Example</title>
<style>
#wrapper {
width: 650px;
height: 500px;
margin: 50px auto;
text-align: center;
}
#myGrid {
height: 100%;
}
/* 헤더 텍스트 가운데 정렬 위함 */
.centered {
.ag-header-cell-label {
justify-content: center !important;
}
}
</style>
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script>
</head>
<body>
<div id="wrapper">
<h1>AG-Grid 꽤 잘 만들었어용</h1>
<div id="myGrid" class="ag-theme-quartz-dark">
</div>
<button onclick="fExp()">내보내깅</button>
</div>
<script>
// 가져오려는 데이터의 컬럼명과 맞춰줘야 한다
const columnDefs = [
{ field: "name", headerName: "이름", sortable: true },
{ field: "alias", headerName: "별명", sortable: true, cellStyle: { textAlign: "left" } },
{ field: "strong", headerName: "장점", cellStyle: { textAlign: "left" } },
{ field: "weak", headerName: "단점", cellStyle: { textAlign: "left" } },
{ field: "birth", headerName: "생일", cellRenderer: MyComp }
];
// 일단 빈 데이터 설정(초기값), 설정 안하면 주구창창 로딩중 메세지
const rowData = [];
// 설정 옵션: 중요, 위에 정의한 것들이 여기서 통합됨에 주목
const gridOptions = {
columnDefs: columnDefs,
rowData: rowData,
defaultColDef: {
flex: 1, // 자동으로 같은 사이즈롱
filter: true,
resizable: true,
minWidth: 100,
headerClass: "centered"
},
// 페이지 설정
pagination: true,
//paginationAutoPageSize:true, // 요게 열려있으면 아래껀 무시당함!
paginationPageSizeSelector: [5, 10, 20], // 원하는 페이지 수 나열
paginationPageSize: 10, // 위에 꺼 중 하나를 선택
onCellClicked: params => {
console.log('cell was clicked', params);
//alert("클릭하신 값은: " + params.value); //요게 있음 뭔가? 방해됨
}
};
function getData() {
var xhr = new XMLHttpRequest();
xhr.open("get", "dummyData.json", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// 데이타 구조 억지 땜빵!
let rslt = JSON.parse(xhr.responseText);
for (let i = 0; i < rslt.length; i++) {
rslt[i].birth = ranDate();
}
//gridOptions.api.setRowData(rslt); // deprecated
gridApi.setGridOption('rowData', rslt); //아래 라인과 동일한 의미
//gridApi.updateGridOptions({ rowData: rslt });
}
}
xhr.send();
}
// csv 내보내기, 별로 안 중요, 그냥 이대로 설정하고 값만 고치면 됨
function fExp() {
var v_params = {
suppressQuotes: "true", // none, true
columnSeparator: " ", // default값이 ,
customHeader: "이름 별명 장점 단점", // 헤더명 추가 출력
customFooter: "이거슨 푸터" // 데이타 아래에 footer추가
};
gridApi.exportDataAsCsv(v_params);
}
// 그리드 셋업
let gridApi;
document.addEventListener('DOMContentLoaded', () => {
const gridDiv = document.querySelector('#myGrid');
// new agGrid.Grid(gridDiv, gridOptions); // deprecated
gridApi = agGrid.createGrid(gridDiv, gridOptions);
getData(); // 데이터 불러오깅
});
function MyComp() {
return this;
}
// AG-GRID 문서에 나오는 커스텀 Cell Renderer
MyComp.prototype.init = function (params) {
this.eGui = document.createElement('div');
this.eGui.innerHTML = `
<input type="date" value="" class="myCal" style="border:0px;width:0px">
<span class="mySpan">${params.value}</span>
`;
this.myCal = this.eGui.querySelector('.myCal')
this.mySpan = this.eGui.querySelector('.mySpan')
this.mySpan.onclick = () => {
this.myCal.showPicker();
}
this.myCal.onchange = () => {
console.log("check", this.myCal.value);
this.mySpan.innerHTML = this.myCal.value;
}
}
MyComp.prototype.getGui = function () {
console.log("check1");
return this.eGui;
}
MyComp.prototype.refresh = function () {
console.log("check2");
return true;
}
MyComp.prototype.destroy = function () {
console.log("check3");
}
function ranDate() {
let now = new Date();
now.setDate(now.getDate() - Math.floor(Math.random() * 90));
let rYear = now.getFullYear();
let rMonth = now.getMonth() + 1;
if (rMonth < 10) rMonth = "0" + rMonth;
let rDate = now.getDate();
if (rDate < 10) rDate = "0" + rDate;
return `${rYear}-${rMonth}-${rDate}`;
}
</script>
</body>
</html>
Load(window.load 이벤트) , DomContentLoaded 차이?(면접질문체크)
window.load(onload) -> 리소스까지 모두 불러오면 발생
DomContentLoaded -> 태그해석만 끝나면 발생(load보다 약간 더 빠르다)
실행 후 확인
cellRenderer
csv -> comma-separated values -> 잘 사용하지 않다가 빅데이터 사용때문에 다시 사용함
(용량이 작다 -> JSON보다도 작다)
주소에서 community -> enterprise(유료버전)로 변경시 사용가능(상업적 용도만 아니면)
선언적 프로그래밍? 미리 짜여진걸 얼마나 잘 가져다 쓰는지
요새는 쿠키를 잘 사용하지 않고 로컬스토리지 , 세션스토리지를 주로 사용한다(왜지 보안문제??)
PWA : Progressive Web Application
로컬스토리지 사용법 알아보기 localStorage.html 생성
<!DOCTYPE html>
<meta charset="UTF-8">
<script>
// localStorage vs sessionStorage
// 영구저장 일시저장(브라우저 종료시 지워짐)
// 사용법은 완전히 동일하다(100% 일치)
// cookie보다 사용법이 쉽고 용량도 커서 점점 더 많이 사용됨(유용하다)
// PMA(Progressive Web Application)의 일부라 할 수 있다
// 객체지향 DB모양(JSON)으로 많이 만들어 사용한다
// 크롬기준으로 사이트당 5MB 정도
// 주로 사용처? 사용자 테마 , 사용자 설정값 등등
/* 기본 제공 명령어!
//localStorage.setItem("name", "현주"); // 쓰기
localStorage.setItem("짝궁", "현장"); // 쓰기
//localStorage.setItem("name", "로또"); // 수정(덮어쓰기 , key값이 같다)
//localStorage.merong="메롱";
// 객체의 속성을 내맘대로 줄 수있다. 위처럼 쓰면 key : merong , value : "메롱"
// alert(localStorage.key(0)); // ??
// alert(localStorage.key(1)); // ??
localStorage.removeItem("name"); // key값에 해당하는 value값을 지운다
//alert(localStorage.getItem("name"));
//alert(localStorage.getItem("짝궁"));
//alert(localStorage.length); // ??
//localStorage.clear(); // 싹다 지운다
*/
</script>
제한사항? Object를 직접 저장이 불가능하다 , string만 저장 가능 -> 직렬화/역직렬화 해야함
// 제한사항 : Object를 직접 저장 할 수 없음 , 오직 string만 저장가능
// localStorage.setItem("check" , {name:"이렇게 쓰면", alias:"어떻게되나 확인"});
// alert(localStorage.getItem("check"));
// alert({name:"이렇게 쓰면", alias:"어떻게되나 확인"});
// 객체를 저장할 떄는 꼭 문자열로 변환(serialize)해서 저장해야한다
// JSON.stringify
localStorage.setItem("check" , JSON.stringify({name:"이렇게 쓰면", alias:"어떻게되나 확인"}));
localStorage.setItem("check2" ,["인","호","여","친","null"]); // 문제점?
//alert(typeof(localStorage.getItem("check2"))); // 꺼내보면 string타입이다, 아래와같이 작성
localStorage.setItem("check2" ,JSON.stringify(["인","호","여","친","null"])); // 이렇게 작성