如何在D3中频繁收听SSE?

时间:2015-10-02 19:49:29

标签: javascript jquery d3.js server-sent-events

我无法找到在D3中绘制点时获得平滑过渡的方法。我有一个绘制世界地图的脚本。我正在听一个给我经度和经度的服务器。我想在屏幕上绘制事件,使圆圈在1秒内从0增加到10。因为我正在收听服务器,所以我可以在1秒内拥有多个数据点。当前一个点仍在转换时,我该如何绘制另一个点?

这是我提出的代码,但我无法找到一种方法可以将d3类型转换添加到“圆圈”,因为只有在使用d3.data([coords])时才可以。输入()。因为我可以直接更改属性,所以在这里使用d3似乎有些过分。

修改

稍微简化我的问题我决定收集1秒钟的数据,然后一次显示这些点数。但是,我认为我无法理解exit()的本质,因为我的下面的代码并没有删除先前的点并在coords上创造新的点。 Points.exit()。remove不起作用,因为它返回一个大小为0的数组,尽管coords每次都会改变。此外,它会在地图上连续显示第一组数据,之后不会改变任何内容。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script type="text/javascript" src="//code.jquery.com/jquery-1.8.0.min.js"></script>
    <script type="text/javascript">
        $(document).ready(
                function() {
                    sse = new EventSource('/my_event_source');
                    sse.onmessage = function(message) {
                        console.log('A message has arrived!');
                        var data = JSON.parse(message.data);
                        data.data.forEach(function(d){
                          d.lat = +d.lat;
                          d.lg = +d.lg;
                        });
                        console.log(data.data)
                        plot(data.data);
                       }
                })
    </script>

    <style>

.point{
  fill:rgb(247,148, 32);
  stroke:black;
  stroke-width:0.7;
  opacity:0.7;
}
    </style>

    <script type ="text/javascript">
      function draw(geo_data){
        "use strict";
        var margin = 75,
         width = 1920 -margin,
         height = 1080 -margin; 

      var svg = d3.select('body')
                    .append("svg")
                    .attr('class',"main")
                    .attr('width', width+margin)
                    .attr('height', height+margin)

      var svg2 = svg.append('g')
                    .attr('class','map');


      // convrt the long, lat to pixels ()x,y
      var projection = d3.geo.mercator()
                          .scale(220)
                          .translate([width/2, height/1.5]);
      //svg objects
      var path = d3.geo.path().projection(projection);
      var map = svg2.selectAll('path')
                  .data(geo_data.features)
                  .enter()
                  .append('path')
                  .attr('d', path)
                  .style('fill','rgb(9,157,217)')
                  .style('stroke','black')
                  .style('stroke-width', 0.5);

      svg.append("g").attr("class","point");
      }

      function plot(data){
        "use strict";
        var margin = 75,
         width = 1920 -margin,
         height = 1080 -margin;

         var spot = d3.select('svg.main').select("g.point");

        // convrt the long, lat to pixels ()x,y
         var projection = d3.geo.mercator()
                             .scale(220)
                             .translate([width/2, height/1.5]);



          var coords = data.map(function(d) {
            return projection([d.lg, d.lat]);
          });

          var points = spot.selectAll("circle")
                        .data(coords);

          points.exit().remove();

          points.enter()
                .append("circle")
                .classed("circle", true)
                .attr('cx', function(d){return d[0];})
                .attr('cy', function(d){return d[1];})
                .attr('r', 10);
        }
    </script>
  </head>

  <body>
    <script type = "text/javascript">
    /*Use d3 to load the GeoJSON file*/
    d3.json("/static/world_countries.json", draw);
    </script>
  </body>

</html>

1 个答案:

答案 0 :(得分:1)

你应该查看Mike Bostock的Thinking with Joins文章。你遇到的问题是概念化如何使用D3来操作一个项目数组,但只有D3动画最近添加到数组中的新项目。这是通过.data()。enter()命令完成的。

我把你想要实现的目标放在一起,省略了地理方面的维度。该示例有三个主要部分,变量初始化,每次将新项目添加到数组时运行的绘制函数,以及随机添加项目然后调用draw()的服务器模拟。

你会看到所有的魔法都发生在draw()函数中。即使我们反复将不断增长的数据数组传递给函数,该函数也只会动画新添加的数据项。

https://jsbin.com/qoqalufihe/edit?html,output