使用单选按钮过滤数据(动画地图)

时间:2018-06-08 13:17:08

标签: javascript d3.js button gis

我有一个动画滑块地图,它采用纬度/经度数据,并根据建筑物的类型何时竖立显示。目前,我只能显示摩天大楼的数据,但是我希望每个按钮都可以过滤数据,以便"住宅"和#34;医院"同样。

d.skyscrp是从data5001.txt中提取日期数据的内容,然后moment()将数据解析为浏览器要读取的信息。我也需要访问d.residential和d.hospitals。到目前为止,我能够加载数据,但不知道如何使按钮过滤掉我需要的内容。

我在bl.ocks上有一个full working example,所有代码都可用。

Plunker of code located here

enter image description here

下面的Index.html以供参考:

<!DOCTYPE html>
<head>
    <title>Map</title>
<meta charset="utf-8">
<link rel="stylesheet" href="d3.slider.css"/>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="d3.slider.js"></script>

</head>

<body>
        <div id="update">
            <div id="agegrp" class="buttons">
                            <div class="button current" data-val="1" onclick = "updateData()" id = "option" name="updateButton"
                               type="button" value = "Update">Button1</div>
                            <div class="button" data-val="2">Button2</div>
                            <div class="button" data-val="3">Button3</div>
                            <div class="button" data-val="4" style="margin-right:0">Button4</div>
                <div class="clr"></div>
            </div>
        </div><!-- @end #update -->

    <div id="title">
        </div>

    <div id="subtitle">
        </div>

        <div id="axis1985">
            <h8></h8>
            </div>

        <div id="axis1990">
            <h8>1990</h8>
            </div>

            <div id="axis1995">
                <h8>1995</h8>
                </div>

                <div id="axis2000">
                    <h8>2000</h8>
                    </div>

                    <div id="axis2005">
                        <h8>2005</h8>
                        </div>

                        <div id="axis2010">
                            <h8>2010</h8>
                            </div>

                            <div id="axis2015">
                                <h8>2015</h8>
                                </div>

    <div id="slider3">
        </div>

        <div id="slidertextplaceholder"></div>
        <div id="slidertext"></div>


        <div id="option">
    <input name="updateButton"
           type="button"
           value="Update"
           onclick="updateData()" />
</div>

<script>

var width = 960,
    height = 850;

var mapPath = "usa.json";

// Define the div for the tooltip
var div = d3.select("body").append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);

var projection = d3.geo.albersUsa()
    .scale(1080)
    .translate([width / 2, height / 2]);

var path = d3.geo.path()
    .projection(projection);

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

d3.json(mapPath, function(error, us) {
  if (error) return console.error(error);

  svg.append("path")
      .datum(topojson.feature(us, us.objects.land))
      .attr("d", path)
      .attr("class", "land-boundary");

  svg.append("path")
      .datum(topojson.mesh(us, us.objects.counties, function(a, b) { return a !== b && (a.id / 1000 | 0) === (b.id / 1000 | 0); }))
      .attr("d", path)
      .attr("class", "county-boundary");

  svg.append("path")
      .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
      .attr("d", path)
      .attr("class", "state-boundary");


  d3.tsv("data5001.txt")
    .row(function(d) {
      return {
        permalink: d.permalink,
        lat: parseFloat(d.lat),
        lng: parseFloat(d.lon),
        state: d.state,
        fullAddress: d.fullAddress,
        buildingName: d.buildingName,
        skyscrp: moment(d.skyscrp,"YYYY-MM-DD HH:mm"),
        residential: moment(d.residential,"YYYY-MM-DD HH:mm"),
        hospital: moment(d.hospital,"YYYY-MM-DD HH:mm")
            };
    })
    .get(function(err, rows) {
        if (err) return console.error(err);
      window.site_data = rows;
    });
});



//display the sites using "permalink"
var displaySites = function(data) {
  var sites = svg.selectAll(".site")
      .data(data, function(d) {
        return d.permalink;
      });

  sites.enter().append("circle")
      .attr("class", "site")
      .attr("cx", function(d) {
        return projection([d.lng, d.lat])[0];
                        })
      .attr("cy", function(d) {
        return projection([d.lng, d.lat])[1];
            })
                 .on("mouseover", function(d) {
                 div.transition()
                         .duration(200)
                         .style("opacity", .9);
                 div.html("building Name:" + "<br>" + d.buildingName + "<br>" +  "<br>" + "Address:" + "<br>" + d.fullAddress + "<br>")
                        .style("left", (d3.event.pageX) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                 })
             .on("mouseout", function(d) {
                 div.transition()
                        .duration(200)
                      .style("opacity", 0);
            })
  .attr("r", 1)
  .transition().duration(800)
    .attr("r", 7);

  sites.exit()
    .transition().duration(200)
      .attr("r",0)
      .remove();
};

var minDateYear = moment('1985-12-19', "YYYY-MM-DD HH:mm");
var maxDateYear = moment('2017-09-29', "YYYY-MM-DD HH:mm");
var secondsInDay = 60 * 60 * 24;

d3.select('#slider3').call(d3.slider()
  //.axis(true).min("1986").max("2017")
    .axis(false).min(minDateYear).max(maxDateYear)
  .on("slide", function(evt, value) {
    var newData = _(site_data).filter( function(site) {
      return site.skyscrp < value;
    })
    //console.log("New set size ", newData.length);
     //console.log("svg value ", newData);
     document.getElementById("slidertext").innerHTML = "Achieved Goals:  " + newData.length;
    displaySites(newData);
  })
);

document.getElementById("slidertextplaceholder").innerHTML = "Achieved Goals:  " + " ____ " + "buildings";
</script>
</body>

1 个答案:

答案 0 :(得分:0)

您只需将过滤器拉入共享代码即可。

以下是我的意思:

// First, a variable to keep the year we're filtering on.
var yearMin = 0;
// Another one to keep track of the building type we're filtering on.
var buildingType = 'skyscrp';

// Shared function
function filterData() {
  var newData = _(site_data).filter(function(site) {
    return site[buildingType] < minYear;
  });
  displaySites(newData);
  document.getElementById("slidertext").innerHTML =
      "Achieved Goals:  " + newData.length;
}

我做了一些假设,但基本的想法是我过滤年份,也在同一声明中建立类型。

因此,每个按钮都会将buildingType设置为适当的值。设置buildingType的值后,他们会调用filterData();

function buttonClick(filterField) {
  if (filterField !== undefined) {
    console.info('Changing building filter to', filterField);
    buildingType = filterField;
  }
  console.info('Applying filter');
  filterData();
}

然后,对于滑块,您可以像这样修改代码:

d3.select('#slider3').call(d3.slider()
  .axis(false).min(minDateYear).max(maxDateYear)
  .on("slide", function(evt, value) {
    console.info('Changing year filter to', value);
    minYear = value;
    filterData();
  })
);

修改

查看数据,我似乎更有可能要根据所选按钮过滤不同的字段。例如,您现在正在skyscrp上进行过滤,但还有hospitalresidential个字段。

所以,使用与以前相同的策略,我只是改变了filterData函数,产生了一个有效的plunkr

这些是我所做的更改,反映在上面的代码中:

  1. 在前三个按钮中添加了onclick处理程序。每个按钮都通过三个字段名称中的一个发送:skyscrp&#39;,&#39; hospital&#39;或者&#39;住宅&#39;。我还更改了他们的标题以匹配他们应用的过滤器,但是您想要做一些额外的事情来更新屏幕上的样式以显示哪个过滤器处于活动状态 - 我不认为这属于你的问题。
  2. 添加了buttonClick功能,如前所述,只需设置过滤器并调用filterData()。但是,我现在使用数据中的实际字段名称,而不是代表建筑类型的数字。
  3. 更新filterData现在使用该字段进行比较。
  4. 修改2

    现在,在filterData内更新标签,可以提供更加一致的体验。