How can I use 2 range sliders at the same time?

筅森魡賤 提交于 2019-12-11 01:52:40

问题


I want to filter data in the table based on the age and height at the same time using 2 range sliders.

I have implemented 2 range sliders (Age and Height) using d3.slider.js and a dc.dataTable. I want to use these 2 range sliders at the same time, but it seems that they are not working properly.

Also, under the table, there is the text "49 selected out of 49 records". The numbers are not changing while using the sliders.

Code:

    var dataTable = dc.dataTable("table#list");
    var dispatch = d3.dispatch('load','filter');

    d3.json('data.json',function(json){
        dispatch.load(json)
    });

    dispatch.on('load',function(json) {
        var formatNumber = d3.format( ",d");
        var facts = crossfilter(json);
        var dimensionAge = facts.dimension(function(d) {
            return +d.age;
        });
        var accessorAge = function(d) {
            return d.age;
        };
        var dimensionHeight = facts.dimension(function(d) {
            return +d.height;
        });
        var accessorHeight = function(d) {
            return d.height;
        };
        var range = d3.extent(json, accessorAge);
        var range2 = d3.extent(json, accessorHeight);
        var all = facts.groupAll();

        d3.select("div#slider3")
            .call(d3.slider().axis(true).min(range[0]).max(range[1]).value(range)
            .on("slide", function(evt,value) {
                dispatch.filter(value);
                d3.select("#slider3textmin").text(Math.floor(value[0]));
                d3.select("#slider3textmax").text(Math.floor(value[1]))
            }))

        d3.select("div#slider4")
            .call(d3.slider().axis(true).min(range2[0]).max(range2[1]).value(range2)
            .on("slide", function(evt,value) {
                dispatch.filter(value);
                d3.select("#slider4textmin").text(Math.floor(value[0]));
                d3.select("#slider4textmax").text(Math.floor(value[1]))
            }))


        FieldNames = [
            "",
            "Age",
            "Weight",
            "Height",
            "Eye Color",
            "Hair Color",
            "Race",
            "Sex",
            "Annual Income"
        ];

        d3.select("tr#FieldNames").selectAll("th")
            .data(FieldNames)
            .enter()
            .append("th") 
            .append("text")
            .text(function(d){ 
                return d;
            });

        dataTable
            .dimension(dimensionAge)
            .group(function(d) {
                return d.sex;
            })
            .columns([
                function(d) {return "";},
                function(d) {return d.age;},
                function(d) {return d.weight;},
                function(d) {return d.height;},
                function(d) {return d.eyeColor;},
                function(d) {return d.hairColor;},
                function(d) {return d.race;},
                function(d) {return d.sex;},
                function(d) {return formatNumber(d.annualIncome);}
            ]);   

        dispatch.on('filter',function(value){
            dataTable.replaceFilter(dc.filters.RangedFilter(value[0], value[1]));
            dataTable.redraw();
        })

        dc.dataCount(".dc-data-count")
            .dimension(facts)
            .group(all);

        dc.renderAll();

    });

Link to the website

Plunker


回答1:


Original response on the dc.js users group.

Nice use of d3.slider.js - I haven't seen that used with dc.js before.

At a quick glance, I see two problems here. First, you're using one dispatch for both sliders, so both sliders are filtering the age, since that's the dimension of the table. You'd probably want to create another dimension for filtering by height, and you don't really need to attach that to a chart.

Second, instead of just redrawing the chart with dataTable.redraw(), you probably want to call dataTable.redrawGroup() so that all charts in its chart group get redrawn, including the dataCount.

Specifically:

  1. you'll need two filter events in your dispatch

    var dispatch = d3.dispatch('load','filterAge','filterHeight');
    
  2. the age slider will call filterAge

                dispatch.filterAge(value);
    

    and the height slider will call filterHeight

                dispatch.filterHeight(value);
    
  3. the current filter event handler will now handle filterAge and it will call redrawGroup

        dispatch.on('filterAge',function(value){
            dataTable.replaceFilter(dc.filters.RangedFilter(value[0], value[1]));
            dataTable.redrawGroup();
        })
    
  4. we add another filterHeight handler which directly filters dimensionHeight and also redraws the chart group

        dispatch.on('filterHeight',function(value){
            dimensionHeight.filter([value[0], value[1]]);
            dataTable.redrawGroup();
        })
    
  5. Reset All will also have to clear dimensionHeight. (Since this dimension isn't used by any chart, dc.filterAll() won't find it.)

            <a href="javascript: dimensionHeight.filter(null); dc.filterAll(); dc.renderAll();">Reset All</a>
    

Fork of your plunker.




回答2:


this for reset all, the 49 selected out of 49 records already change correcly

replace this

<a href="javascript: dimensionHeight.filter(null); dc.filterAll(); dc.renderAll();">Reset All</a>

to this

<a href="#" onclick="sololo()">Reset All</a>

add this after dispatch on load

dispatch.on('load',function(json) {
//your code
})       

function sololo(){
                   //table
               dispatch.filterAge([0,100]);
               dispatch.filterHeight([0,100]);
               //text slider
               d3.select("#slider4textmin").text(0)
                     d3.select("#slider4textmax").text(0)
                     d3.select("#slider3textmin").text(0);
                     d3.select("#slider3textmax").text(0)
                     //slider
                     d3.select('#slider3').select('#handle-one').style('left','0%')
               d3.select('#slider3').select('#handle-two') .style('right','0%')
               d3.select('#slider3').select('div').style('left','0%').style('right','0%') 
                     d3.select('#slider4').select('#handle-one').style('left','0%')
               d3.select('#slider4').select('#handle-two') .style('right','0%')
               d3.select('#slider4').select('div').style('left','0%').style('right','0%') 
    }


来源:https://stackoverflow.com/questions/46024705/how-can-i-use-2-range-sliders-at-the-same-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!