Создание изменяющегося в реальном времени прямоугольника в d3.js с помощью биткойна WebSocket

У меня есть доступ к биткойн-сетке, которая каждую минуту дает мне текущую рыночную цену за биткойны. Я хочу создать один прямоугольник, который динамически меняется на эти значения, передаваемые в данный момент в мой массив bardata.

Вот код:

<html>
<script type="text/javascript" src="js/d3.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>


<body>

    <script>
        var webSocket = new WebSocket('wss://socket.cbix.ca/index'); //creating a websocket connection to blockhain.info
        webSocket.onopen = function (event) {
            console.log('Websocket connection open');
        };

        var bardata = [];

        webSocket.onmessage = function (event) {
            var e = jQuery.parseJSON(event.data);
            console.log(e);
            var high = e.high;
            console.log(high);
            update();
            bardata.push(high);
            $('.message').prepend("<p>" + "The highest bitcoin value for this minute is: $" + high + "</p>");

        }



        var height = 730
            , width = 1080
            , barWidth = 50
            , barOffset = 5;

        var yScale = d3.scale.linear()
            .domain([0, d3.max(bardata + 100)])
            .range([0, height])

        var svg = d3.select('body').append('svg')
            .attr('width', width)
            .attr('height', height)
            .style('background', '#C9D7D6')

        function update() {
            svg.selectAll('rect').data(bardata)
                .enter().append('rect')
                .style('fill', '#C61C6F')
                .attr('width', barWidth)
                .attr('height', function (d) {
                    return yScale(d);
                })
                .attr('x', function (d, i) {
                    return i * (barWidth + barOffset);
                })
                .attr('y', function (d) {
                    return height - yScale(d);
                }).transition()
                .attr('height', function (d) {
                    return yScale(d);
                })
                .attr('y', function (d) {
                    return height - yScale(d);
                })
                .delay(function (d, i) {
                    return i * 20;
                })
                .duration(1000)
                .ease('elastic')
        }
    </script>
    <div class="message">
    </div>


</body>

</html>

Однако, когда я запускаю этот код, каждый раз создается новая панель. Я знаю, что это связано с функцией обновления, перерисовывающей все .onmessage функция обновляется снова. Мне было интересно, есть ли другой способ сделать это, возможно, с использованием AJAX или что-то? Некоторая помощь будет принята с благодарностью.

1 ответ

Решение

Проблема в том, что ваша update Функция имеет только "ввод" выбора. В этой ситуации ожидаемое поведение имеет только 1 неизменяемый столбец (поскольку выбор "ввод" пуст со второго раза). Но когда вы подталкиваете ценности к barData длина этого barData Массив увеличивается, и столбцы, которые вы видите, являются новыми вариантами ввода.

Итак, первое изменение использует только последнее значение barData, а не весь массив.

Второе изменение - это запись правильного ввода и обновление выбора. Вот как ты должен делать. Сначала свяжем данные:

var rect = svg.selectAll("rect")
    .data([data]);

Затем создайте свой выбор "ввод":

rect.enter()
    .append("rect").attr("x", 0)
    .attr("y", 25)
    .attr("height", 50)
    .attr("width", d => scale(d))
    .attr("fill", "#C61C6F");

Этот выбор ввода будет работать только при первом вызове update, Со второго раза вы будете изменять только существующую панель:

rect.transition()
    .duration(200)
    .ease('elastic')
    .attr("width", d => scale(d));

Вот демо:

setInterval(() => {
    var data = ~~(Math.random() * 100)+1;
    update(data);
}, 2000);



var svg = d3.select("#svg")
    .append("svg")
    .attr("width", 300)
    .attr("height", 100);

var text = d3.select("#text");

var scale = d3.scale.linear()
    .range([0, 300])
    .domain([0, 100]);

update(50);

function update(data) {

    var rect = svg.selectAll("rect")
        .data([data]);

    rect.enter()
        .append("rect").attr("x", 0)
        .attr("y", 25)
        .attr("height", 50)
        .attr("width", d => scale(d))
        .attr("fill", "#C61C6F");

    rect.transition().duration(500).ease('elastic').attr("width", d => scale(d));

    text.text("The highest bitcoin value for this minute is: $" + data)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="text"></div>
<div id="svg"></div>

Другие вопросы по тегам