在d3.js中的同一数据集上实现多个过滤器

时间:2018-11-15 17:57:04

标签: javascript html d3.js leaflet

我希望就如何在我拥有的d3 /传单地图上的同一数据集(但两个不同的属性)上实现多个范围滑块过滤器获得一些建议。

我希望能够使用范围滑块按日期过滤地图上的点,并使用另一个范围滑块按“大小”过滤地图上的点。目前,我进行此设置的方法仅适用于按日期过滤。本质上,当实例化时间滑块时,它会从一个函数传入不透明度值,该函数可以将点的不透明度动态设置为零,从而将其滤除。这是基本代码:

//Build time-slider in HTML
<div  id="sliderContainer"> 
<input id="timeslide-leaflet" type="range" min="0" max="25" value="0" step="1" /><br>

//Define years for time slider
var inputValue = null;
var years = ["1993","1994","","","" ];

        //load in data
        SFData.forEach(function(d) {
        var coords = d.geometry.coordinates
        console.log(coords)
        d.latLong = new L.LatLng(coords[1],
                                coords[0]);

    })

    //draw map circles
    var feature = mapG.selectAll("circle")
        .data(SFData)
        .enter().append("circle")
        .attr("class", 'features')

    //if time-slider moved, call update function
    d3.select("#timeslide-leaflet").on("input", function() {        
        update(+this.value);   
    });

    //Update function sets feature's opacity and can filter by making invisible
    function update(value) {
        document.getElementById("range-leaflet").innerHTML=years[value];
        inputValue = years[value];

        d3.selectAll(".features")
            .attr("opacity", dateMatch)       
}


    function dateMatch(data, value) {

    //do some internal calculations based on my data

    if (yearInt <= inputValueInt && yearExpirationInt >= inputValueInt) {

        return ".7";
    } else {
        return "0"; //return opacity 0 for data that should be filtered out 
    };
}

我希望能够以类似的方式在不同的属性(大小)上过滤相同的数据。我可以轻松创建另一个时间滑块-但是如何将另一个返回的不透明度值传递给地图要素.attr(“ opacity”)?本质上,我可以编写与dateMatch()类似的函数,该函数按大小进行过滤,我不确定如何将返回的不透明度值传递回地图要素,因为dateMatch()已经传递了值。

谢谢!

1 个答案:

答案 0 :(得分:-1)

使功能链接不透明

d3.selectAll(".features")
    .attr("opacity", calcOpacity);

function calcOpacity(d) {
    var opacity = dateOpacity(d, 1);
    return c2Opacity(d, opacity);
}

function dateOpacity(d, opacity) {
    if (opacity === 0.0) return opacity;
    // calcs
    return (yearInt <= inputValueInt && yearExpirationInt >= inputValueInt) ? 0.7 : 0.0;
}

function c2Opacity(d, opacity) {
    if (opacity === 0.0) return opacity;
    // calcs
    return Math.random() < 0.5 ? 0.7 : 0.0;
}

修改

我已经删除了DiamondJoe12对此答案的编辑,并放置了一个片段,该片段使用2个滑块来过滤图表中的圆圈。

滑块提供所需的yearsize值,我看不出使用查找数组的原因。

滑块的最低值被用作通过所有特定过滤器的标记。

该片段显示了一个svg,其中包含500个不同大小和不同年份数据的圆圈。

var svgWidth = 500, svgHeight = 500;

var svg = d3.select("body")
  .append("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight);

var color = d3.scaleOrdinal(d3.schemeCategory10);
var x = d3.scaleLinear().domain([-0.1, 1.1]).range([0, svgWidth]);
var y = d3.scaleLinear().domain([-0.1, 1.1]).range([0, svgHeight]);

var data = d3.range(500).map(i => ({x:Math.random(), y:Math.random(),
    year: 1993 + Math.floor(Math.random()*26),
    size: 4 + Math.floor(Math.random()*7) }));

svg.selectAll(".features")
    .data(data)
  .enter()
  .append("circle")
    .attr("class", "features")
    .attr("cx", d => x(d.x))
    .attr("cy", d => y(d.y))
    .attr("r", d => d.size)
    .attr("fill", (d, i) => color(i));

//if time-slider moved, call update function
d3.select("#timeslide-leaflet").on("input", function() {
    update();
});

d3.select("#sizeslide-leaflet").on("input", function() {
    update();
});

update();

//Update function sets feature's opacity and can filter by making invisible
function update() {
    var year = +document.getElementById("timeslide-leaflet").value;
    year = year === 1992 ? 0 : year;
    document.getElementById("time-leaflet").innerHTML = year === 0 ? "All" : year;

    var size = +document.getElementById("sizeslide-leaflet").value;
    size = size === 3 ? 0 : size;
    document.getElementById("size-leaflet").innerHTML = size === 0 ? "All" : size;

    svg.selectAll(".features")
      .transition()
      .duration(200)
        .attr("opacity", d => calcOpacity(d, year, size) );
}

function calcOpacity(d, year, size) {
    var opacity = dateOpacity(d, year, 1);
    return sizeOpacity(d, size, opacity);
}

function dateOpacity(d, year, opacity) {
    if (opacity === 0.0) return opacity;
    if (year === 0)  return opacity; // All pass
    return (d.year === year) ? 0.7 : 0.0;
}

function sizeOpacity(d, size, opacity) {
    if (opacity === 0.0) return opacity;
    if (size === 0)  return opacity; // All pass
    return d.size === size ? 0.7 : 0.0;
}
.features {
stroke:black;
stroke-width:0.5;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="sliderContainer"> 
<input id="timeslide-leaflet" type="range" min="1992" max="2018" value="1992" step="1" /><br/>
<input id="sizeslide-leaflet" type="range" min="3" max="10" value="3" step="1" />
</div>
<div>
<div>Year: <span id="time-leaflet"></span></div>
<div>Size: <span id="size-leaflet"></span></div>
</div>