添加过滤,搜索和分页的实时流表

Adding filtering, searching and pagination to realtime streaming table

本文关键字:实时 分页 过滤 搜索 添加      更新时间:2023-09-26

我有一个使用节点提供的数据实时更新的表。表是用d3.js渲染的。

我的问题是,我不知道如何添加过滤,搜索和分页功能的表使用d3.js。我是一个乞丐,很难理解哪里是放置代码的最佳位置。我一直在考虑使用外部库来完成它,但如果我找到一种方法来使用d3.js,它会更好更干净。

这是我的代码:

var table = d3.select('#data')
table.append('thead')
    .append('tr')
    .selectAll('th')
        .data(['Title', 'Visits', 'Sales', 'Conversion(%)'])
    .enter()
        .append('th')
        .text(function (d) { return d })
table.append('tbody')
function setupData(data) {
    var rows = d3.select('tbody')
        .selectAll('tr')
        .data(data, function(d) { return d.title })
    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')
    var td = rows.selectAll('td')
        .data(function(d) { return d3.map(d).entries() })
        .attr('class', function (d) { return d.key })
    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).toFixed(2) + '%';
            }
            return d.value
        })
}

var socket = io();
//var data = [];
socket.on('sellers-'.concat(<%= seller %>), function(msg){
    var data = [];
    var seller = $.parseJSON(msg);
    var items = seller['items'];
    for(item in items) {
        var item_data = items[item];
        data.push({'title': item_data['title'], 'today_visits': item_data['today_visits'], 'sold_today': item_data['sold_today'], 'conversion_rate': item_data['conversion_rate']});
    }
    setupData(data);
    //setupData(JSON.parse(msg).items)
});

看起来你的主要D3图表渲染方法已经设置为使用一般更新模式,所以你应该很好地去那里。

过滤和搜索的最佳选择可能只是使用原生JavaScript解决方案。只要用过滤后的数据集调用setupData方法,图表就会更新。例如:

var allData;
var loadItems = function(items) {
    var item;
    allData = [];
    for (item in items) {
        allData.push(item);
    }
}
var filterMatching = function(matcher) {
    var item;
    var filteredData = [];
    for (item in allData) {
        if (matcher(item)) filteredData.push(item);
    }
    setupData(filteredData);
}
// filter on conversion rate
filterMatching(function(item) { return item.conversion_rate > 0.5; });
// search on title
filterMatching(function(item) { return /foobar/.test(item); });

分页有点棘手,但仍然非常简单。你只需要做一点数学运算。

var itemsPerPage = 10;
var numberOfPages() {
    return Math.ceil(allData.length / itemsPerPage);
}
var goToPage(pageNumber) {
    var firstIndex = (pageNumber - 1) * itemsPerPage;
    var pageItems = allData.slice(firstIndex, firstIndex + itemsPerPage);
    setupData(pageItems);
}

现在让它们很好地一起工作可能需要一些努力。

或者,你可以考虑使用像Crossfilter这样的库,它可以很好地与D3配合使用。在Crossfilter:

中,您的过滤和分页可能看起来像这样
var filter = crossfilter(records);
var conversion_rate = filter.dimension(function(d) { return d.conversion_rate; });
var title = filter.dimension(function(d) { return d.title; });
// filter on a dimension
conversion_rate.filterRange([0.5, 1]);
title.filterFunction(function (d) { return /foobar/.test(d); });
// take the top x of a dimension
conversion.group().top(5);

如果你有很多数据要过滤,使用交叉过滤器会快得多。然而,由于一开始就将所有数据绘制成图表,因此似乎没有那么多数据,因此使用原生JavaScript手工处理可能是一种方法。