在d3正交投影上从csv旋转点

时间:2015-04-09 13:14:07

标签: javascript csv svg d3.js orthogonal

我一直试图将热图与csv加载的数据投影到D3上的正交投影上。在旋转地球(即D3,正交投影)时,点/圆保持静止。我尝试了很多组合,但未能弄清楚缺少什么。

基本上,我需要小圈子沿着国家的道路前进。

以下是完整的代码:

<script>

  var width = 600,
  height = 500,
  sens = 0.25,
  focused;

  //Setting projection

  var projection = d3.geo.orthographic()
  .scale(245)
  .rotate([0,0])
  .translate([width / 2, height / 2])
  .clipAngle(90);

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

  //SVG container

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

  // Define the gradient
    var gradient = svg.append("svg:defs")
    .append("svg:linearGradient")
    .attr("id", "gradient")
    .attr("x1", "0%")
    .attr("y1", "0%")
    .attr("x2", "100%")
    .attr("y2", "100%")
    .attr("spreadMethod", "pad");

    // Define the gradient colors
    gradient.append("svg:stop")
    .attr("offset", "0%")
    .attr("stop-color", "#FFFF00")
    .attr("stop-opacity", 0);

    gradient.append("svg:stop")
    .attr("offset", "100%")
    .attr("stop-color", "#FF0000")
    .attr("stop-opacity", 1);



  //Adding water
  svg.append("path")
  .datum({type: "Sphere"})
  .attr("class", "water")
  .attr("d", path)


  var countryTooltip = d3.select("body").append("div").attr("class", "countryTooltip"),
  countryList = d3.select("body").append("select").attr("name", "countries");

  queue()
  .defer(d3.json, "world-110m.json")
  .defer(d3.tsv, "world-110m-country-names.tsv")
  .await(ready);

  //Main function

  function ready(error, world, countryData) {

    var countryById = {},
    countries = topojson.feature(world, world.objects.countries).features;


    //Adding countries to select

    countryData.forEach(function(d) {
      countryById[d.id] = d.name;
      option = countryList.append("option");
      option.text(d.name);
      option.property("value", d.id);
    });

    //circles for heatmap are coming from the csv below

    d3.csv("cities.csv", function(error, data) {
       svg.selectAll("circle")
       .data(data)
       .enter()
       .append("a")
          .attr("xlink:href", function(d) {
            return "https://www.google.com/search?q="+d.city;}
          )
       .append("circle")
       .attr("cx", function(d) {
               return projection([d.lon, d.lat])[0];
       })
       .attr("cy", function(d) {
               return projection([d.lon, d.lat])[1];
       })
       .attr("r", 5.5)
       .attr('fill', 'url(#gradient)');



    var world = svg.selectAll("path.circle")
    .data(countries) //countries from the tsc file is used to populate the names
    .enter().append("path")
    .attr("class", "land")
    .attr("d", path)
    //.attr('fill', 'url(#gradient)')

    //Drag event

    .call(d3.behavior.drag()
      .origin(function() { var r = projection.rotate(); return {x: r[0] / sens, y: -r[1] / sens}; }) 
      .on("drag", function() {
        var rotate = projection.rotate();
        projection.rotate([d3.event.x * sens, -d3.event.y * sens, rotate[2]]);
        svg.selectAll("path.land").attr("d", path);
        svg.selectAll(".focused").classed("focused", focused = false);
      }))

    //Mouse events

    .on("mouseover", function(d) {
      countryTooltip.text(countryById[d.id])
      .style("left", (d3.event.pageX + 7) + "px")
      .style("top", (d3.event.pageY - 15) + "px")
      .style("display", "block")
      .style("opacity", 1);
    })
    .on("mouseout", function(d) {
      countryTooltip.style("opacity", 0)
      .style("display", "none");
    })
    .on("mousemove", function(d) {
      countryTooltip.style("left", (d3.event.pageX + 7) + "px")
      .style("top", (d3.event.pageY - 15) + "px");
    });
     });//closing d3.csv here

    //Country focus on option select

    d3.select("select").on("change", function() {

      var rotate = projection.rotate(),
      focusedCountry = country(countries, this),
      p = d3.geo.centroid(focusedCountry);

      svg.selectAll(".focused").classed("focused", focused = false);

    //Globe rotating

    (function transition() {


      d3.transition()
      .duration(2500)
      .tween("rotate", function() {
        var r = d3.interpolate(projection.rotate(), [-p[0], -p[1]]);
        return function(t) {
          projection.rotate(r(t));
          svg.selectAll("path").attr("d", path)
          .classed("focused", function(d, i) { return d.id == focusedCountry.id ? focused = d : false; });
          //svg.selectAll("circle").attr("d", data)
          //.classed("focused", function(d, i) { return d.id == focusedCountry.id ? focused = d : false; });
        };
      })

      })();
    });

    function country(cnt, sel) { 
      for(var i = 0, l = cnt.length; i < l; i++) {
        if(cnt[i].id == sel.value) {return cnt[i];}
      }
    };

  };
  </script>

请帮忙。

提前谢谢

1 个答案:

答案 0 :(得分:0)

这是一个使用点几何的选项:

.enter().append('path')
  .attr('class', 'circle_el')
  .attr('fill', function(d) {return d.fill; })
  .datum(function(d) {
    return {type: 'Point', coordinates: [d.lon, d.lat], radius: some_radius};
  })
  .attr('d', path);

这很酷,因为您将使用路径重绘同时更新圈子。此外,它会将投影视为一个球体,而不是显示应该位于球体不可见侧的圆圈。我从杰森戴维斯的post得到了这个想法。