달력

5

« 2024/5 »

  • 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
  • 31
반응형

날짜의 분기(Quarter)를 구해서 자동으로 달력 input에 매핑해 주면

실 사용자들이 편리하겠다라는 생각이 들어서 바로 작업을 진행하였다.

 

분기의 규칙만 알면 간단하게 진행할 수 있었는데 수학적으로 표현하자면

1/1 ~ 3/31은 1분기, 

4/1 ~ 6/30은 2분기,

7/1 ~ 9/30은 3분기,

10/1 ~ 12/31은 4분기 이므로 분기 시작 월을 구하려면 다음과 같은 규칙을 꺼낼 수 있었다.

현재 분기 = 현재 월/3의 소수점 1번째 자리 올림
분기 시작 월 = (현재 분기 - 1)* 3 + 1

 

하지만 javascript에서 월은 0~11로 표현되므로 아래 소스코드의 수식으로 변환되었다.

(분기도 0~3으로 표현되도록 함)

var quarter = parseInt(date.getMonth() / 3);
var startMonth = quarter * 3;

 

분기 끝 날짜를 구하려면 시작일에 2개월을 더하고 해당 월의 마지막 날짜를 구한다.

var endDate = getMonthLastDate(new Date(addMonths(new Date(startDate), 2)));

 

이전/다음 분기는 분기마다 3개월 씩 차이나므로 현재 날짜의 월에 3씩 이동해서 구하면 된다.

(단, 3월 31일에 3개월을 더할 경우 6월 31일이 되는데 이는 존재하지 않는 날짜로 js에서 7월 1일으로 자동 변환된다.

때문에 날짜를 1일로 셋팅하고 구해야 일(day)에 따른 버그가 생기지 않는다.)

var date = addMonths((new Date(now.setDate(1))), count*3);

 

그렇게 완성된 소스코드는 다음과 같다.

<script type="text/javascript">
	function getQuarterStartDate(date) {
		var year = date.getFullYear();
		var quarter = parseInt(date.getMonth() / 3);
		var startMonth = quarter * 3;
		
		return (new Date(year, startMonth, 2)).toISOString().substring(0, 10);
	}
	
	function getMonthLastDate(date) {
		
		return (new Date(date.getFullYear(), date.getMonth()+1, 1)).toISOString().substring(0, 10);
	}

	function addMonths(orgDate, count) {
		
		return (new Date(orgDate.setMonth(orgDate.getMonth() + count))).toISOString().substring(0, 10);
	}
	
	function setDate(startId, endId, count) {
		var now = new Date();
		var date = addMonths((new Date(now.setDate(1))), count*3);
		var startDate = getQuarterStartDate(new Date(date));
		var endDate = getMonthLastDate(new Date(addMonths(new Date(startDate), 2)));

		$("#"+startId).val(startDate);
		$("#"+endId).val(endDate);
	}
	
	var quarterCnt = 0;
	
	function moveQuarter(count) {
		quarterCnt += count;
		setDate("startDate", "endDate", quarterCnt);
	}
	
	$(function() {
		setDate("startDate", "endDate", quarterCnt);
	});
</script>
<html>
    <body>
        <button type="button" onClick="moveQuarter(-1)">◀</button>
        <input type="text" id="startDate" name="startDate" readonly/>
        <input type="text" id="endDate" name="endDate" readonly/>
        <button type="button" onClick="moveQuarter(1)">▶</button>
    </body>
</html>

 

반응형
:
Posted by 리샤씨
반응형

가끔가다, 파일 첨부 시 첨부된 파일의 용량을 보여줘야 할 때가 있다.

보통 파일 첨부 시 알 수 있는 것은 로우한 파일 크기인데,

필요한 건 해당 값을 1024로 나눈 값인 KB/MB/GB 등등이다.

 

처음엔 JS에서만 사용했었는데 최근 flutter에서도 필요하게 되어 두 가지 버전을 공유한다.

 

javascript 버전

function spaceFormat(spaceValue, decimalPoint){
	var fileSizeNmList = ["Byte", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
	var fileSizeNmIndex = 0;
	
	while (spaceValue > 1024 && fileSizeNmIndex < fileSizeNmList.length) {
		spaceValue /= 1024;
		fileSizeNmIndex++;
	}
	
	if (spaceValue.toFixed != undefined) {
		spaceValue = spaceValue.toFixed(decimalPoint);
	}
	return spaceValue + fileSizeNmList[fileSizeNmIndex];
}

 

flutter 버전

String spaceFormat(double spaceValue, int decimalPoint){
  List<String> fileSizeNmList = ["Byte", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
  int fileSizeNmIndex = 0;

  while (spaceValue > 1024 && fileSizeNmIndex < fileSizeNmList.length) {
    spaceValue /= 1024;
    fileSizeNmIndex++;
  }

  return spaceValue.toStringAsFixed(decimalPoint) + fileSizeNmList[fileSizeNmIndex];
}

 

반응형
:
Posted by 리샤씨
반응형

웹 개발을 하다 보면 보통 처음엔 퍼블리싱을 받지만

어쩔 수 없이 추가 개발이 들어와 기존에 있던 ui를 확장하여 새로운 ui 작업을 하기도 한다.

ui 고칠 일이 많거나 새로운 아이콘이 필요하다거나 잘 모르겠으면

퍼블리셔 분에게 요청하겠지만 간단한 것은 빠르게 내 선에서 해결하는 편이다.

 

이것도 그런 일 중 하나로, 관리자 페이지 특정 목록에서 엑셀 일괄 등록 기능이 새로 추가되는 일이었다.

엑셀 파일로 데이터를 업로드하여 진짜 테이블에 넣기 전에 임시 테이블에 넣어 확인하는 ui가 있었는데

엑셀로 등록하다 보니 나중에 행의 개수가 많아져 header가 고정되는 편이 좋을 것 같아 그렇게 작업했다.

 

처음엔 그냥 y축만 움직여서 작업하면 되어서 css로 충분히 작업이 가능하였으나

x축이 필요한 테이블이 생기게 되어 jQuery를 이용하는 아래 결과물이 나오게 되었다.

<style>
#userTbl {
  	width: 600px;
	height: 200px;
  	overflow-y: auto;
}
  	
#userTblHead {
  	width: 600px;
  	overflow-x: hidden;
}
  	
#userTbl table {
  	border-top: 0px;
}
  	
#userTblHead table {
  	overflow: hidden;
  	border-top: 2px solid #aaa;
  	border-bottom: 1px solid #aaa;
}
  	
.tblWrap table {
  	width: 100%;
  	border-spacing: 0;
  	border-width: 1px 0;
  	border-collapse: collapse;
  	table-layout: fixed;
}

.tblWrap table thead th {
	background: #eee;
}

.tblWrap table td {
	text-align: center;
	border-bottom: 1px solid #aaa;
}

.tblWrap table td.left {
	text-align: left;
	padding-left: 10px;
}

.tblWrap table th:not(:last-child), table td:not(:last-child) {
    border-right: solid 1px #aaa;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
var sl = 0;
$(function(){
	$.fn.hasYScrollBar = function() {
	    return (this.prop("scrollHeight") == 0 && this.prop("clientHeight") == 0)
	            || (this.prop("scrollHeight") > this.prop("clientHeight"));
	};

	$.fn.hasXScrollBar = function() {
	    return (this.prop("scrollWidth") == 0 && this.prop("clientWidth") == 0)
	            || (this.prop("scrollWidth") > this.prop("clientWidth"));
	};
	
	$("#userTbl").scroll(function(event){
		// data 테이블 x축 스크롤을 움직일 때header 테이블 x축 스크롤을 똑같이 움직인다
		if (sl != $("#userTbl").scrollLeft()) {
			sl = $("#userTbl").scrollLeft();
			$("#userTblHead").scrollLeft(sl);
		}
	});
	
	if ($("#userTbl").hasYScrollBar()) {
		//y축 스크롤이 있으면 스크롤 넓이인 17px만큼 header 마지막 열 크기를 늘린다
		$("#userTblHead colgroup col:last-child").width($("#userTbl colgroup col:last-child").width() + 17);
	} else {
		$("#userTblHead colgroup col:last-child").width($("#userTbl colgroup col:last-child").width());
	}
});
</script> 
<div class="tblWrap">
	<div id="userTblHead">
		<table>
			<!-- col의 width를 %가 아닌 px 단위로 정확히 지정해야 두 테이블이 하나의 테이블 처럼 보인다 -->
			<colgroup>
				<col style="width:45px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:150px">
				<col style="width:200px">
				<col style="width:130px">
				<col style="width:130px">
			</colgroup>
			<thead>
				<tr>
					<th>No</th>
					<th>이름</th>
					<th>부서</th>
					<th>직급</th>
					<th>아이디</th>
					<th>전화번호</th>
					<th>이메일</th>
					<th>생년월일</th>
					<th>입사일</th>
				</tr>
			</thead>
		</table>
	</div>
	<div id="userTbl">
		<table>
			<colgroup>
				<col style="width:45px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:100px">
				<col style="width:150px">
				<col style="width:200px">
				<col style="width:130px">
				<col style="width:130px">
			</colgroup>
			<tbody>
				
				<tr>
					<td>1</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>2</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>3</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>4</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>5</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>6</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>7</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>8</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
				<tr>
					<td>9</td>
					<td>홍길동</td>
					<td>영업</td>
					<td>사원</td>
					<td>hong</td>
					<td>010-1000-1000</td>
					<td class="left">hong@company.co.kr</td>
					<td>1994-09-15</td>
					<td>2017-05-08</td>
				</tr>
			</tbody>
		</table>
	</div>
</div>

 

- y축 있을 때

No 이름 부서 직급 아이디 전화번호 이메일 생년월일 입사일
1 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
2 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
3 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
4 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
5 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
6 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
7 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
8 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
9 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08

 

- y축 없을 때

No 이름 부서 직급 아이디 전화번호 이메일 생년월일 입사일
1 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
2 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08
3 홍길동 영업 사원 hong 010-1000-1000 hong@company.co.kr 1994-09-15 2017-05-08

 

아시다시피 html table은 header가 기본적으로 고정되지 않지만 위와 같이 편법을 쓰면 가능하다.

table header를 고정시키는 편법으로는 여러 가지 방법이 있으나

위 방법처럼 접근성엔 좋지 않은 header 테이블과 data 테이블을 나눈 이유는

내가 적용하려는 웹이 관리자 페이지이므로 접근성이 크게 상관없고,

저 방법으로 하면 ie와 Chrome 둘 다 열을 나누는 선이 있어도 y축이 있든 없든 예쁘게 보이기 때문이다.

반응형
:
Posted by 리샤씨
2020. 1. 3. 09:30

Chart.js Pie 데이터 값 출력 개발/Chart.js2020. 1. 3. 09:30

반응형

어제 통계를 살펴보니, pie 데이터 값 출력이라는 정보를 찾는 키워드를 발견하여 글 작성합니다.

piece label이라는 Chart.js 확장 플러그인을 사용하면 되는데,

https://github.com/emn178/chartjs-plugin-labels/tree/master/src

위 링크를 타고 들어가면 js가 있습니다.

 

사용법은 아래와 같습니다.

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js"></script>
<script type="text/javascript" charset="utf-8" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="/com/js/Chart.PieceLabel.js"></script> <!-- your piecelabel -->
<script type="text/javascript">
var num = Math.random();
  var data = {
      labels: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"],
      datasets: [
          {
              data: [
                Math.random(),
                Math.random(), 
                Math.random(), 
                Math.random(), 
                Math.random(), 
                Math.random(), 
                Math.random(),
                Math.random(),
                Math.random(),
                Math.random()
              ],
              backgroundColor: [
      	        "#f79546",
       	        "#9bba57",
                "#4f81bb",
                "#5f497a",
                "#a94069",
                "#ff5f34",
                "#41774e",
                "#003663",
       	        "#49acc5",
       	        "#c0504e"
              ],
	          borderWidth: 0,
	          label: "Dataset 1"
          }]
  };
   
  window.onload = function() {
    var ctx8 = $('#chart8').get(0).getContext("2d");
    window.theChart8 = new Chart(ctx8, {
        type: 'pie',
        data: data,
        options: {
                responsive: true,
                legend: false,
                maintainAspectRatio : false,
                animation: false,
                pieceLabel: {
                  mode:"label",
                  position:"outside",
                  fontSize: 11,
                  fontStyle: 'bold'
               }
        }
    });
</script>
<div style="width:150px">
  <canvas id="chart8"></canvas>
</div>

간단히 설명하자면, options의 pieceLabel이 Pie 차트의 데이터 값을 표시하는 기능입니다.

mode에 따라 label/value/percentage(default)/image를 표시할 수 있고

position에 따라 default(default)/border/outside 값이 표시될 위치를 지정할 수 있습니다.

position : default / outside

또한, Pie 차트뿐만 아니라 Doughnut, polarArea, Bar 차트에서도 사용 가능합니다.

 

출처 : https://stackoverflow.com/questions/42164818/chart-js-show-labels-on-pie-chart

반응형
:
Posted by 리샤씨
반응형

※ 해당 글은 아래 글과 연결되어 있습니다.

혹시 잘 안되거나 이해 안 되는 부분이 있으시면 아래 글을 참조하여 주세요.

http://risha-lee.tistory.com/18?category=764955

 

 

 

앞서 말했다시피 사용자 범례를 이전 글처럼 만들기만 해서는 

위 그림처럼 범례 클릭 시 해당 데이터셋의 숨김/보이기 토글 기능을 사용할 수 없다.

 

해당 기능을 만들려면 이전 글의 코드에 다음과 같이 추가로 코드를 작성해주어야 한다.

 

<script>
	 window.onload = function() {
		$("#chartLegend li").click(function(){
			updateDataset(event, $(this).attr("datasetIndex"), "theChart");
			if($(this).css("text-decoration").indexOf("line-through")<0){
				$(this).css("text-decoration", "line-through");
			} else{
				$(this).css("text-decoration", "none");
			}
		});
	 }

	 //범례 클릭시 해당 데이터셋이 숨김/보이기 토글 기능 함수
	 function updateDataset(e, datasetIndex, chartId) {
		var index = datasetIndex;
		var ci = e.view[chartId];
		var meta = ci.getDatasetMeta(index);
		var scaleList = ci.options.scales["yAxes"];
        
		meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
		ci.update();
	 }
</script>

 

참고 : https://github.com/chartjs/Chart.js/issues/2565

 

반응형
:
Posted by 리샤씨
반응형

Chart.js가 기본적으로 제공하는 범례는 그냥 위치를 위나 아래로 정하면 무조건 가운데 정렬만 할 뿐,

왼쪽 위. 오른쪽 위, 오른쪽 아래, 왼쪽 아래 등 위치를 자유자재로 변경할 수 없어서 

오른쪽 위에 범례를 두기 위해 사용자 범례를 사용했었다.

물론 디자인도 자유자재로 변경할 수 있다는 점이 마음에 들어서 위치를 바꿀 겸 범례의 디자인도 조정하였다.

 

추가로 덧붙이자면 Chart.js에서 제공하는 기본 범례를 사용하면 그래프가 길어져 스크롤이 생겼을 때,

스크롤 위치에 따라 어떤 부분에서는 범례가 보이지만 어떤 부분에서는 범례가 보이지 않을 수 있다.

사용자 범례를 사용하면 위의 문제점도 해결해준다. (차트를 좌우로 스크롤해도 범례의 위치는 고정된다)

 

1. 막대 차트&막대 라인 차트 - 막대 형식 데이터셋 원형, 라인 형식 데이터셋 선형 범례

2. 라인 차트 - 라인 형식 데이터셋 사각형 범례

 

별다른 설정 없이 막대 차트냐, 라인 차트냐, 해당 데이터셋의 형식이 라인이냐 바이냐에 따라 자동으로 class를 입히도록 작성하였다.

아래의 코드를 사용하면 위와 같은 범례를 만들 수 있다. 예제는 막대 라인 차트이다. 

 

<style type="text/css">
.chartjs-legend ol,
.chartjs-legend ul {
  list-style: none;
  margin:0;
  padding:0;
  text-align:right;
}

.chartjs-legend li {
  cursor:pointer;
  display: inline-table;
  margin: 10px 4px;
}

.chartjs-legend li span.bar{
  position:relative;
  padding: 0px 10px;
  margin: 5px;
  border-radius:100px;
  color:white;
}

.chartjs-legend li span.line{
  position:relative;
  padding: 1px 10px;
  margin: 5px;
  color:white;
}

.chartjs-legend li div.line{
	float:left;
	height:2px;
	background:#000;
	font-size:0;
	line-height:0;
	width:25px;
	padding:1px 0px;
	border-radius:100px;
	margin: 9px 5px;
}
</style>

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js"></script>
<script>       
	var barChartData = {        
	        labels: ["January", "February", "March", "April", "May", "June", "July"],
	        datasets: [{
	            type: 'line',
	            label: 'line',
	            borderColor: "#1E90FF",
	            fill: false,
	            data: [
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000
	           ]
	        }, 
	        {
	            type: 'bar',
	            label: 'bar',
	            backgroundColor: "#F7464A",
	            data: [
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000,
	                Math.random()*90000
	            ]
	        }]
	    };
	
	 window.onload = function() {
	    var ctx = $('#chart').get(0).getContext("2d"); 
	    window.theChart = new Chart(ctx, {
	         type: 'bar',
	         data: barChartData,
	         options: {
	             legend: false,
	             legendCallback: function(chart){
	                return drawCustomLegend(chart);
	             }// 사용자 범례를 만들 때 쓰는 함수를 지정하거나 작성한다.
	         }
	    });
	    $('#chartLegend').html(window.theChart.generateLegend());//사용자 범례 자리에 해당 차트에 대한 사용자 범례 코드를 넣는다.
	 }
	 
	 function drawCustomLegend(chart){
    	var text = [];
    	text.push('<ul class="' + chart.id + '-legend">');
    	if(chart.config.type == 'bar'){//막대차트, 막대라인차트일 경우
    		var barIndex = chart.data.datasets.length;
        	for (var i = 0; i <chart.data.datasets.length; i++) {
        		if(chart.data.datasets[i].type == 'line' == false){
        			barIndex = i;
        			break;
        		}
        	}//라인 형식 데이터셋이 어디까지인지 확인
        	// -> 막대 형식의 데이터셋을 라인 형식의 데이터셋보다 앞에 둘 경우 라인이 막대에 묻히기 때문에 라인 형식이 먼저 올 수 밖에 없다.
        	//그러나 막대 형식의 데이터셋의 범례를 먼저 그리고 싶었기 때문에 해당 작업을 했다.
        	
        	for (i = barIndex; i <chart.data.datasets.length; i++) {
        		if(!(chart.data.datasets[i].hideLegend) && chart.data.datasets[i].label){
        			text.push('<li  datasetIndex="'+i+'"><span class="bar" style="background-color:' + chart.data.datasets[i].backgroundColor + '" ></span>');
        			text.push('<span>'+chart.data.datasets[i].label+'</span>');
        			text.push('</li>');
        		} 
        	}//막대 형식 데이터셋의 범례를 먼저 그림
        	
        	for (i = 0; i <barIndex; i++) {
        		if(!(chart.data.datasets[i].hideLegend) && chart.data.datasets[i].label){
        			text.push('<li datasetIndex="'+i+'"><div class="line" style="background:' + chart.data.datasets[i].borderColor + '"></div>');
        			text.push('<span>'+chart.data.datasets[i].label+'</span>');
        			text.push('</li>');
        		} 
        	}//막대 형식 데이터셋의 범례를 그린 후 라인 형식 데이터셋의 범례를 그림.
    	} else if(chart.config.type == 'line'){//라인 차트일 경우
    		for (i = 0; i <chart.data.datasets.length; i++) {
        		if(!(chart.data.datasets[i].hideLegend) && chart.data.datasets[i].label){
        			text.push('<li datasetIndex="'+i+'"><span class="line" style="background-color:' + chart.data.datasets[i].borderColor + '"></span>');
        			text.push('<span>'+chart.data.datasets[i].label+'</span>');
        			text.push('</li>');
        		} 
    		}
    	}
      	text.push('</ul>');
      	return text.join("");
    }
</script>

<div id="chartArea" style="width:700px;">  
	<div id="chartLegend" class="chartjs-legend"></div>
	<canvas id="chart"></canvas>
</div>

 

그러나 이것만 해서는.. 기본 범례에서 제공하는 범례를 클릭하면 

해당 데이터셋의 숨김/보이기 토글이 작동하지 않아 다소 불편했다.

그래서 나는 사용자 범례에 해당 기능도 추가했었다.

 

다음 글에서 설명하도록 하겠다.

반응형
:
Posted by 리샤씨
반응형

chart.js에서 그래프 위에 값 그리는 법도 역시 Chart.plugins.register를 확장해서 아래와 같이 사용한다.

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.bundle.min.js"></script>
<script type="text/javascript">
Chart.plugins.register({
  afterDraw: function (chart, easing) {
    if (chart.config.options.showValue) {
        var ctx = chart.chart.ctx;
        var fontSize = chart.config.options.showValue.fontSize || "9";
        var fontStyle = chart.config.options.showValue.fontStyle || "Arial";
        ctx.font =  fontSize + "px " + fontStyle;
        ctx.textAlign = chart.config.options.showValue.textAlign || "center";
        ctx.textBaseline = chart.config.options.showValue.textAlign || "bottom";
	
        chart.config.data.datasets.forEach(function (dataset, i) {
            ctx.fillStyle = dataset.fontColor || chart.config.options.showValue.textColor || "#000";
            dataset.data.forEach(function (data, j) {
               if(dataset.hideValue != true){
                	var txt = Math.round(data*100)/100;
                	var xCoordinate = dataset._meta[chart.id].data[j]._model.x;
                	var yCoordinate = dataset._meta[chart.id].data[j]._model.y;
                	var yCoordinateResult;

                	if(dataset.type == 'line'){
                		yCoordinateResult = yCoordinate + 21 > chart.scales[chart.options.scales.xAxes[0].id].top ? chart.scales[chart.options.scales.xAxes[0].id].top :  yCoordinate + 21;
                	} else{
                		yCoordinateResult = yCoordinate - 10;
                	}
                	ctx.fillText(txt, xCoordinate, yCoordinateResult);
                }
             });
          });
        }
      }
    }
});

var barChartData = {
        labels: ["label1", "label2", "label3", "label4"],
        datasets: [{
            label: 'Dataset 1',
            backgroundColor: ["rgba(220,220,220,0.5)", "navy", "red", "orange"],
            data: [
                Math.random(),
                Math.random(),
                Math.random(),
                Math.random()
            ]
      }]
};
	
window.onload = function() {
	var ctx5 = $('#chart5').get(0).getContext("2d");
	window.theChart5 = new Chart(ctx5, {
            type: 'bar',
            data: barChartData,
            options: {
                responsive: true,
                legend: {
                	display: false
                },
                scales: {
                	xAxes: [{
                		  gridLines: {
                		    display: false
                		  },
                		}],
	                yAxes: [{
	                	gridLines: {
                		    drawBorder: false//축과 데이터의 경계선 표시 여부
                		  },
	                    ticks: {
	                    	display: false,//축의 값 표시 여부
	                        max: 1,
	                        min: 0
	                    }
	                  }]
                },
                animation:false,
                showValue:{
                fontStyle: 'Helvetica', //Default Arial
                fontSize: 20
	     }
       }
 });
</script>
<div>
	<canvas id="chart5"></canvas>
</div>

 

반응형
:
Posted by 리샤씨
반응형

지난번에 말한 대로 Chart.plugins.register를 이용해서 chart.js의 반도넛 차트 안에 숫자를 적을 수 있다.

방법은 다음과 같은 소스를 도넛 차트를 그리는 js에 넣고 도넛 차트 옵션에 elements.center를 만들면 된다.

(이전 포스팅 참조 : chart.js에서 반도넛 그래프 그리는 법)

Chart.plugins.register({
  beforeDraw: function (chart) {
	  if (chart.config.options.elements.center) {
	      //Get ctx from string
	      var ctx = chart.chart.ctx;

	      //Get options from the center object in options
	      var centerConfig = chart.config.options.elements.center;
	      var fontSize = centerConfig.fontSize || '50';
	      var fontStyle = centerConfig.fontStyle || 'Arial';
	      var txt = centerConfig.text;
	      var color = centerConfig.color || '#000';
	      var sidePadding = centerConfig.sidePadding || 20;
	      var sidePaddingCalculated = (sidePadding/100) * (chart.innerRadius * 2)
	      //Start with a base font of 30px
	      ctx.font = fontSize + "px " + fontStyle;

	      //Get the width of the string and also the width of the element minus 10 to give it 5px side padding
	      var stringWidth = ctx.measureText(txt).width;
	      var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated;

	      // Find out how much the font can grow in width.
	      var widthRatio = elementWidth / stringWidth;
	      var newFontSize = Math.floor(30 * widthRatio);
	      var elementHeight = (chart.innerRadius * 0.7);

	      // Pick a new font size so it will not be larger than the height of label.
	      var fontSizeToUse = Math.min(newFontSize, elementHeight);

	      //Set font settings to draw it correctly.
	      ctx.textAlign = 'center';
	      ctx.textBaseline = 'middle';
	      var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2);
	      var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2);

	      //반도넛일 경우
	      if (chart.config.options.rotation === Math.PI && chart.config.options.circumference === Math.PI) {
	        centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 1.3);
	      }
	      ctx.font = fontSizeToUse+"px " + fontStyle;
	      ctx.fillStyle = color;

	      //Draw text in center
	      ctx.fillText(txt, centerX, centerY);
	    }
  }
});

 

 

만약 숫자가 너무 올라가있거나 내려가 있으면 38번 줄의 수식을 변경해주면 된다.

 

출처 : https://stackoverflow.com/questions/20966817/how-to-add-text-inside-the-doughnut-chart-using-chart-js

반응형
:
Posted by 리샤씨


반응형
반응형