차근차근/JAVA Script

상승하는 그래프 chart.js

예쁜꽃이피었으면 2025. 1. 3. 14:15

https://www.chartjs.org/

 

Chart.js

Simple yet flexible JavaScript charting library for the modern web

www.chartjs.org

 

https://kr.pinterest.com/pin/722194490271491419/ 

 

motion animated footage statistics bars columns Stock Footage Video [Video] | Motion graphs, Business infographic, Graphing

Ad: motion animated footage. Statistics bars columns growth, arrow up. Finance, Business Infographic animation, Bar graph going up, Profit concept, positive increase chart, arrows axis, white background

kr.pinterest.com

요구사항 디자인을 받았는데 위 링크와 비슷한 느낌으로 움직이는 그래프가ㅏ 필요하다고 한다..

 

[ 조건 ]

1. 화면 위에서 아래로 이동하는 스크롤 일 때만 작동한다. 아래에서 위로 갈 때에는 그래프 그려진 상태 유지

2. 해당 영역 진입 직전에 이미 그래프가 있다면 초기화 후 다시 작성

 

 

 

...
<div class="chart-container" style="height:800px;"> <!-- 높이값이 없으면 그래프 제대로 안나옴 -->
		<canvas id="MainChart"></canvas>
</div>
...

 

	/* 그래프 영역 시작*/
	//data 설정

	const data = [
	    { x: 0, y: 5 },
	    { x: 5, y: 10 },
	    { x: 10, y: 4 },
	    { x: 15, y: 15},
	    { x: 20, y: 20 },
		{ x: 25, y: 35 },
	    { x: 30, y: 25 },
	    { x: 35, y: 55 },
		{ x: 40, y: 75 },
		{ x:45, y: 110 },
		{ x: 50, y: 140 },
		{ x: 55, y: 185 },
		{ x: 60, y: 265 },
	];
	
	//애니메이션 설정
    const totalDuration = 1000; 
	const delayBetweenPoints = totalDuration / data.length;
    const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
    let chartanimationStarted = false;//그래프 모션 시작 여부를 추적하는 플래그
    const animation = {
        x: {
            type: 'number',
            easing: 'linear',
            duration: delayBetweenPoints,
            from: NaN, // the point is initially skipped
            delay(ctx) {
                if (ctx.type !== 'data' || ctx.xStarted) {
                    return 0;
                }
                ctx.xStarted = true;
                return ctx.index * delayBetweenPoints;
            }
        },
        y: {
            type: 'number',
            easing: 'linear',
            duration: delayBetweenPoints,
            from: previousY,
            delay(ctx) {
                if (ctx.type !== 'data' || ctx.yStarted) {
                    return 0;
                }
                ctx.yStarted = true;
                return ctx.index * delayBetweenPoints;
            }
        }
    };
    
    
    let width, height, gradient;
    function getGradient(ctx, chartArea){
    	const chartWidth = chartArea.right - chartArea.left;
    	const chartHeight = chartArea.bottom - chartArea.top;
    	if(!gradient || width !== chartWidth || height !== chartHeight){
    		width = chartWidth;
    		height = chartHeight;
    		
    	    var gradient = ctx.createLinearGradient(0 , chartArea.top, 0, chartArea.bottom );
    	    //점점 진해짐
    	    gradient.addColorStop(1,'rgba(85,51,34,0.3)');
    	    gradient.addColorStop(0.9,'rgba(144,65,25,0.5)');
    	    gradient.addColorStop(0.5,'rgba(243,91,15,1)');
    		
    	}
    	
    	return gradient;
    }
    
    
	
	//환경설정
    const config = {
            type: 'line',
            data: {
                datasets: [{//datasets여기에 중괄호 두개넣으면 그래프 두개 생기는 지 확인 필요 + NaN하면 포인터 안찍힘
                	////그라데이션 추가 20240102
//                  borderColor: "#E66132",
                	borderColor : function(context){
                		const chart = context.chart;
                		const {ctx, chartArea} = chart;
                		
                		if(!chartArea){
                			return
                		}
                		return getGradient(ctx, chartArea);
                	},
                    borderWidth: 5,
                    data: data,
                    //포인트 설정
//                  radius: 0,//0인 경우 포인트 사용하지 않음
                    pointStyle : 'circle',
                    pointRadius : 5,
                   // pointBorderColor : '#E66132',
                   // backgroundColor : '#E66132',
                    pointBorderColor : function(context){ //점에도 그라이데이션 추가
                		const chart = context.chart;
                		const {ctx, chartArea} = chart;
                		
                		if(!chartArea){
                			return
                		}
                		return getGradient(ctx, chartArea);
                	},
                	backgroundColor : function(context){ //점에도 그라이데이션 추가
                		const chart = context.chart;
                		const {ctx, chartArea} = chart;
                		
                		if(!chartArea){
                			return
                		}
                		return getGradient(ctx, chartArea);
                	},
                    
                }]
            },
            options: {
    			//가로 사이즈 변경 시 새로 만들기 위해 추가 시작
    			//캔버스 영역 chart-container으로 감싸야 한다.
    			responsive: true,
                maintainAspectRatio: false,////차트 그래프 사이즈 고정
    			// maintainAspectRatio : true 이면 가로 넓이가 변경되어도 처음 생성된 크기로 고정
    			// maintainAspectRatio: false 이면 가로 넓이에 따라 그래프 수정
    			
    			//가로 사이즈 변경 시 새로 만들기 위해 추가 종료				
    		    animation,
                interaction: {
                    intersect: false
                },
    			events: [''],//마우스오버 이벤트 없앰
    			plugins: {
                    legend: {display : false}
    			},
                scales: {
                    x: {
                        type: 'linear',
    					grid:{//그리드 안보이게
    						display : false,
    					},
    					 border: {
    					  display: false,
    					},
    					ticks: {
    					  //color: 'blue',
    					  display: false,
    					}					
                    },//x
    				y: {
                        type: 'linear',
    					grid:{//그리드 안보이게
    						display : false
    					},
    					 border: {
    					  display: false,
    					},
    					 ticks: {
    					  //color: 'blue',
    					  display: false,
    					}
                    }	//y
                }//scales
            }
        };
    
    
    
	var myChart = new Chart(
	        document.getElementById('MainChart'),
	        config
	    );
	
	function onScroll(){

		var  chart_04_Top = document.querySelector("# chart_04").offsetTop;
		var  chart_01_Bottom = document.querySelector("# chart_01").offsetTop; //다음 영역 시작 위치

		if(( chart_04_Top <= window.scrollY+700) && ( chart_01_Bottom >= window.scrollY) && !chartanimationStarted)  {

			const chartStatus = Chart.getChart(" MainChart");
			if(chartStatus == undefined){ //그래프가 없으면 생성
					myChart = new Chart(
					document.getElementById(' MainChart'),
					config
				);
					
					
			}
			
			chartanimationStarted = true;	
		}
		
		
		//애니메이션 초기화
		var motionResetArea = document.querySelector("#motionReset").offsetTop;
		
		if((window.scrollY + window.innerHeight <= motionResetArea) && chartanimationStarted){
			chartanimationStarted = false;
			myChart.destroy(); //그래프 초기화
		}
	}
	
	window.addEventListener('scroll',onScroll);
	
	/* 그래프 영역 종료*/
반응형