0

socketio を使用して redis チャネル (販売者) からデータを消費し、リアルタイムでデータをフロントエンドにプッシュするアプリを作成しました。データセットには最大 1000 行を含めることができるので、データテーブルを使用してデータをきれいに表現することを考えています。テーブル要素は定期的に更新されますが、追加/削除する行はなく、更新のみが行われます。

私が直面している問題は、ビジュアライゼーション エコシステムの経験が浅いため、どの方法を実装するのが適切なのかがわからないことです。私はd3jsをいじっていましたが、何かをすぐに準備するのは難しすぎると思います.datatables jsライブラリも使用しようとしましたが、データテーブルをリアルタイムにする方法がわかりませんでした.

これは、フロント エンドからのコードの抜粋です。

socket.on('sellers', function(msg){
  var seller = $.parseJSON(msg);
  var sales = [];
  var visits = [];
  var conversion = [];
  var items = seller['items'];

  var data = [];
  for(item in items) {
    var item_data = items[item];
    //data.push(item_data)
    data.push([item_data['title'], item_data['today_visits'], item_data['sold_today'], item_data['conversion-rate']]);
  }

  //oTable.dataTable(data);

  $(".chart").html("");
  drawBar(data);
});
4

1 に答える 1

2

d3 を使用して問題を解決するのは、シンプルかつエレガントです。今朝、少し時間をかけて、自分のニーズに適応できるフィドルを作成しました。

http://jsfiddle.net/CelloG/47nxxhfu/

d3 を使用するには、データを html 要素に結合する方法を理解する必要があります。著者による簡単な説明については、http://bost.ocks.org/mike/join/を参照してください。

フィドルのコードは次のとおりです。

var table = d3.select('#data')

// set up the table header
table.append('thead')
    .append('tr')
    .selectAll('th')
        .data(['Title', 'Visits', 'Sold', 'Conversion Rate'])
    .enter()
        .append('th')
        .text(function (d) { return d })

table.append('tbody')

// set up the data
// note that both the creation of the table AND the update is
// handled by the same code.  The code must be run on each time
// the data is changed.

function setupData(data) {
    // first, select the table and join the data to its rows
    // just in case we have unsorted data, use the item's title
    // as a key for mapping data on update
    var rows = d3.select('tbody')
        .selectAll('tr')
        .data(data, function(d) { return d.title })

    // if you do end up having variable-length data,
    // uncomment this line to remove the old ones.
    // rows.exit().remove()

    // For new data, we create rows of <tr> containing
    // a <td> for each item.
    // d3.map().values() converts an object into an array of
    // its values
    var entertd = rows.enter()
        .append('tr')
            .selectAll('td')
                .data(function(d) { return d3.map(d).values() })
            .enter()
                .append('td')

    entertd.append('div')
    entertd.append('span')

    // now that all the placeholder tr/td have been created
    // and mapped to their data, we populate the <td> with the data.

    // First, we split off the individual data for each td.
    // d3.map().entries() returns each key: value as an object
    // { key: "key", value: value}
    // to get a different color for each column, we set a
    // class using the attr() function.

    // then, we add a div with a fixed height and width
    // proportional to the relative size of the value compared
    // to all values in the input set.
    // This is accomplished with a linear scale (d3.scale.linear)
    // that maps the extremes of values to the width of the td,
    // which is 100px

    // finally, we display the value.  For the title entry, the div
    // is 0px wide
    var td = rows.selectAll('td')
        .data(function(d) { return d3.map(d).entries() })
        .attr('class', function (d) { return d.key })

    // the simple addition of the transition() makes the
    // bars update smoothly when the data changes
    td.select('div')
        .transition()
        .duration(800)
        .style('width', function(d) {
            switch (d.key) {
                case 'conversion_rate' :
                    // percentage scale is static
                    scale = d3.scale.linear()
                        .domain([0, 1])
                        .range([0, 100])
                    break;
                case 'today_visits': 
                case 'sold_today' :
                    scale = d3.scale.linear()
                    .domain(d3.extent(data, function(d1) { return d1[d.key] }))
                    .range([0, 100])
                    break;
                default:
                    return '0px'
            }
            return scale(d.value) + 'px'
        })
    td.select('span')
        .text(function(d) {
            if (d.key == 'conversion_rate') {
                return Math.round(100*d.value) + '%'
            }
            return d.value
        })
}

setupData(randomizeData())

d3.select('#update')
    .on('click', function() {
        setupData(randomizeData())
    })

// dummy randomized data: use this function for the socketio data
// instead
//
// socket.on('sellers', function(msg){
//  setupData(JSON.parse(msg).items)
// })
function randomizeData() {
    var ret = []
    for (var i = 0; i < 1000; i++) {
        ret.push({
            title: "Item " + i,
            today_visits: Math.round(Math.random() * 300),
            sold_today: Math.round(Math.random() * 200),
            conversion_rate: Math.random()
        })
    }
    return ret
}
于 2015-05-16T17:28:11.930 に答える