flask에서 만든 데이터로 d3js 애니메이션 만들기.

1 분 소요

애니메이션을 만듭시다.

  • python 에서 애니메이션, 즉 각 프레임별로 필요한 데이터를 전송하고, 각 프레임을 만드는 작업을 해보려고 합니다.
  • html 페이지를 만들어줍니다.
    • 처음에는 어떻게 하나 싶었는데 그냥 i를 하나씩 올려주면서 진해하면 되더군요…
<html>
    <head>
        <script src="https://d3js.org/d3.v5.js"></script>
    </head>
    <body>
        <svg id='chart1'>
        </svg>
        <script>
            var chart1 = d3.select('#chart1').attr('width', 750).attr('height', 750);
            var chart1_data_lst = {{ circle_data_lst| tojson}};
            var i=0;
            // d3.interval를 이용해서 animation을 만들어주고, 
            var animation = d3.interval(
                function(elapsed){
                    // 종료조건을 설정해주고.
                    if(i==chart1_data_lst.length){
                        this.stop();
                    }else{
                        frame_data_lst = chart1_data_lst[i];
                        //console.log(frame_data_lst);
                        chart1.selectAll('circle').data(frame_data_lst)
                            .attr('cx', function (d) { return d['cx'] })
                            .attr('cy', function (d) { return d['cy'] })
                            .attr('r', function (d) { return d['r'] })
                            .attr('fill', function (d) { return d['fill'] })
                            .attr('stroke', function (d) { return d['stroke'] })
                            .attr('stroke-width', function (d) { return d['stroke-width'] })
                            .attr('fill-opacity', function (d) { return d['fill-opacity'] })
                            .enter().append("circle")
                            .attr('cx', function (d) { return d['cx'] })
                            .attr('cy', function (d) { return d['cy'] })
                            .attr('r', function (d) { return d['r'] })
                            .attr('fill', function (d) { return d['fill'] })
                            .attr('stroke', function (d) { return d['stroke'] })
                            .attr('stroke-width', function (d) { return d['stroke-width'] })
                            .attr('fill-opacity', function (d) { return d['fill-opacity'] })
                        // 아래처럼 i를 올리면서 진행해줍니다. 
                        i = i + 1;
                    }
                }, 100)
        </script>
    </body>
</html>

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/random_animation')
def random_animation():
    import numpy as np

    circle_data_lst = []
    ## 30개의 프레임을 만듭니다. 
    for frame in range(0, 30):
        each_frame = []
        ## 각 프레임별로 들어가는 데이터, 즉 원은 총 200개이며, 200개에 필요한 데이터를 모두 넘겨줍니다.
        for i in range(0, 200):
            each_frame.append(
                {
                    "cx": np.random.random()*750,
                    "cy": np.random.random()*750,
                    "r": (np.random.random()+1)*20,
                    "stroke": "black",
                    "stroke-width": 3,
                    "fill": f"rgb({np.random.randint(0, 256)}, {np.random.randint(0, 256)}, {np.random.randint(0, 256)})",
                    "fill-opacity": 0.3,
                }
            )
        circle_data_lst.append(each_frame)
    ## 최종적으로 프레임 리스트, 그리고 프레임에는 프레임에 필요한 다양한 데이터들이 들어가 있는 딕셔너리를 html에 넘겨줍니다.
    return render_template('d3_animation.html', circle_data_lst=circle_data_lst)

wrap-up

  • 사실 좀 더 파볼 필요는 있습니다. 저는 한 페이지 내에 같은 타임축을 공유하는 여러 요소를 만들어야 하는데 흠…생각해보니 그냥 하면 될것 같군요.
  • 여담이지만, 이런식으로 랜덤하게 그림을 만드는데 생각보다 되게 예뻐요. 마음에 듭니다. 프레임을 한 20000개를 만들어봤는데 그래도 생각보다는 시간이 많이 걸리지 않습니다.
  • 그리고, 트랜지션을 좀더 정리해보면 좋을 것 같습니다 하하.

reference

댓글남기기