자바스크립트로 원형게이지에 캔틀스틱 차트를 입히고 싶습니다.

조회수 1181회

이미지

안녕하세요. 자바스크립트로 차트 UI를 만들어야 하는데 너무 막막해서 조언을 구하고 싶습니다.

위 그림과 같이 실시간으로 들어오는 데이터에 따라 원형 게이지 차트 위에 캔들스틱 차트를 그려야 하는데 계속 찾아도 비슷하게 구현된 라이브러리를 못찾겠습니다.

이러한 차트를 그려보셨거나, 비슷한 라이브러리를 사용했던 분 혹시 계신지 어쭈어보고 싶습니다.

  • (•́ ✖ •̀)
    알 수 없는 사용자

2 답변

  • 원형 캔들 차트 라이브러리는 딱히 본 적이 없는데... 도넛 차트를 응용해서 만들 수 있지 않을까요?

    근데 단순히 이걸 구현하려고 라이브러리를 배우고 되는지 시도해 보고 하는 삽질 하느니 직접 구현하는게 나을 것 같기도 하고요.

    직접 구현한다면 구현 난이도는 다 비슷하겠지만 표현을 뭘로 하느냐의 차이긴 해요.

    canvas를 쓰시면 가능할거에요. https://www.w3schools.com/tags/canvas_arc.asp

    완벽하게 맞아 떨어지는 라이브러리를 찾지 못한다면 저는 이게 가장 쉬워보입니다.

    차선책으로 SVG기반으로 하는 라이브러리를 사용하셔도 됩니다. (SVG 엘리먼트 및 속성을 직접 다루는건... 음... 딱히 추천드리지 않습니다.)

    CSS와 일반적인 엘리먼트로만 만드는건... 만들기도 번거로울 뿐더러 만들어놔도 컨트롤하기 힘들겁니다. border-radius: 50% 속성 부여된 동심원들 잘 스까치면 가능은 할거에요.

    • 답변 감사합니다. canvas로 일일히 그려서 알고리즘 싸움(?)을 통해 완성했습니다. 알 수 없는 사용자 2020.5.20 21:52
  • 결국 canvas 를 통해 완성했습니다. 혹시나 필요하신 분을 위해 작성합니다.

    완성된 그림과 코드를 첨부합니다.

    아직 완벽히 다짠게 아닌것에 유의해 주시면 감사하겠습니다.

    이미지

    <html>
    <head>
    </head>
    <body>
    <canvas id="tempCanvas" width=700 height=500>
        </canvas>
    </body>
    </html>
    
    var circular ={
        width:700, //캔버스 너비
        height:500, //캔버스 높이
        radius:200, // 그리려는 원의 반지름
        lineWidth:1, // 원의 두께
        angle:0.35, // 원의 각도
        MinVal:0,  // 원의 최소값
        MaxVal:100, //원의 최대값
        toMaxVal:50, //처음 그릴때의 최대 초기값
        toMinVal:50 // 처음 그릴때의 최소 초기값
    };
    $(document).ready(function(){
        testDraw(49, 51); // 디버그용 그리기
        setInterval(function(){
            var Number1 = Number((Math.random()*100).toFixed(0));
            var Number2 = Number((Math.random()*100).toFixed(0));
            var openVal, closeVal;
            if(Number1 > Number2){
                openVal = Number2;
                closeVal = Number1;
            }else{
                openVal = Number1;
                closeVal = Number2;
            }
            testDraw(openVal, closeVal);
        },2000)
    });
    
    var req;
    function testDraw(openVal, closeVal){
        var canvas = document.getElementById("testCanvas");
        var context = canvas.getContext("2d");
    
        drawStarndard(context);
    
        drawCircle(circular.toMinVal, circular.toMaxVal, context);
        animate(openVal, closeVal, canvas, context);
    }
    
    function drawStarndard(context){
        //기준선 
        context.beginPath();
        context.arc(circular.width/2, circular.height/2, circular.radius, (1-circular.angle)*Math.PI, (2+circular.angle)*Math.PI, false)
        context.lineWidth=1;
        context.strokeStyle="#000000";
        context.stroke();
        context.beginPath();
    
        // hit 최소값
        context.moveTo((circular.width/2 - circular.radius),circular.height/2);
        context.lineTo((circular.width/2 - circular.radius)-30, circular.height/2);
        context.stroke();
        context.font = "20px Arial";
        context.fillText("25", (circular.width/2 - circular.radius)-65,(circular.height/2)+5);
    
        //중앙값
        context.beginPath();
        context.moveTo(circular.width/2, circular.height/2-circular.radius)
        context.lineTo(circular.width/2, circular.height/2-circular.radius-30);
        context.stroke();
        context.fillText("50", (circular.width/2)-10,(circular.height/2 - circular.radius-40));
    
        // hit 최대값 
        context.beginPath();
        context.moveTo(circular.width/2+circular.radius, circular.height/2)
        context.lineTo(circular.width/2+circular.radius+30, circular.height/2);
        context.stroke();
        context.fillText("75", (circular.width/2 + circular.radius)+40,(circular.height/2)+5);
    }
    
    function animate(openVal, closeVal, canvas, context) {
    
        if(openVal < circular.toMinVal){
            circular.toMinVal -= 1;
        }else if(openVal > circular.toMinVal){
            circular.toMinVal += 1;
        }
        if(closeVal > circular.toMaxVal){
            circular.toMaxVal += 1;
        }else if(closeVal < circular.toMaxVal){
            circular.toMaxVal -= 1;
        }
    
        context.clearRect(0, 0, canvas.width, canvas.height);
    
        drawStarndard(context);
    
        drawCircle(circular.toMinVal, circular.toMaxVal, context);
    
        if(openVal == circular.toMinVal && closeVal == circular.toMaxVal){
            cancelAnimationFrame(req);
            circular.toMinVal = openVal;
            circular.toMaxVal = closeVal;
        }else{
            req = requestAnimationFrame(function() {
              animate(openVal, closeVal, canvas, context);
            });
        }
    }
    
    function drawCircle(openVal, closeVal, context){
        var openAngle = getAngle(circular.angle, circular.MinVal, circular.MaxVal, openVal);
        var closeAngle = getAngle(circular.angle, circular.MinVal, circular.MaxVal, closeVal);
    
        context.beginPath();
        context.arc(circular.width/2, circular.height/2, circular.radius+5, openAngle , closeAngle, false);
        context.lineWidth=5;
        context.strokeStyle="#3536f0";
        context.stroke();
    
        context.beginPath();
        context.moveTo((Math.cos(openAngle)*circular.radius) + (circular.width/2) , (Math.sin(openAngle)*circular.radius) + (circular.height/2));
        context.lineTo((Math.cos(openAngle)*circular.radius*1.2) + (circular.width/2) , (Math.sin(openAngle)*circular.radius*1.2) + (circular.height/2));
        context.stroke();
    }
    
    • (•́ ✖ •̀)
      알 수 없는 사용자

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)