使用D3,如何在平移后更新地图上的圆圈?

时间:2013-09-23 20:17:06

标签: javascript d3.js geometry maps

我正在使用D3制作地图。我已经在地图上添加了点和圆圈。当我平移地球(这是一个立体地图)时,点会更新到新位置,但圆圈会发生变化。如何以与圈子类似的方式更新积分?

我使用以下方法添加点和圆圈:

// POINTS
svg.append("g").attr("class","points")
    .selectAll("text").data(places.features)
    .enter().append("path")
    .attr("class", "point")     
    .style("pointRadius", 2)
    .style("fill", "red");

// CIRCLES
svg.append("g").attr("class","circles")
    .selectAll("path").data(places.features)      
    .enter().append("circle")        
    .attr('cx', function(d) { return proj(d.geometry.coordinates)[0]})
    .attr('cy', function(d) { return proj(d.geometry.coordinates)[1]})    
    .attr("r", 4)   
    .style('fill', 'green')
    .attr("d", path); 

然后在平移地图时,我调用一个名为refresh的函数来更新这些对象:

function refresh() {

      // redraw land
      svg.selectAll(".land").attr("d", path);  

      // redraw circles
      svg.selectAll(".point").attr("d", path.projection(proj));

      // redraw circles
      svg.selectAll(".circles").attr("d", path.projection(proj));  

    }

此处显示了一个工作示例(需要链接world-110m.json才能使其生效)。我应该以不同的方式添加圈子,以便重绘它们吗?

<!DOCTYPE html>
<meta charset="utf-8">

<style>
.land {

  fill: rgb(117, 87, 57);
  stroke-opacity: 1;
  stroke: #fff;
  stroke-width: 0.75;
}

</style>
<head>

  <!-- libraries -->
  <script src="http://d3js.org/d3.v3.min.js"></script>
  <script src="http://d3js.org/queue.v1.min.js"></script>
  <script src="http://d3js.org/topojson.v0.min.js"></script>

</head>

<body>
  <div class="map"></div>
</body>

<script>

// Lots of code from:
// http://bl.ocks.org/3757125
// http://bl.ocks.org/3795040

// data
var places = {"type": "FeatureCollection","features": [
{ "type": "Feature", "properties": { "id": 34, "status": 1}, "geometry": { "type": "Point", "coordinates": [  55.321249, 24.104000 ] }},
{ "type": "Feature", "properties": { "id": 34, "status": 1}, "geometry": { "type": "Point", "coordinates": [  55.321249, 24.104000 ] }},
{ "type": "Feature", "properties": { "id": 272, "status": 1}, "geometry": { "type": "Point", "coordinates": [  54.002962, 23.455742 ] }},
{ "type": "Feature", "properties": { "id": 272, "status": 1}, "geometry": { "type": "Point", "coordinates": [  54.002962, 23.455742 ] }},
{ "type": "Feature", "properties": { "id": 350, "status": 1}, "geometry": { "type": "Point", "coordinates": [ 136.321249,-24.496000 ] }},
{ "type": "Feature", "properties": { "id": 427, "status": 0}, "geometry": { "type": "Point", "coordinates": [ 136.321249,-26.296000 ] }},
{ "type": "Feature", "properties": { "id": 427, "status": 0}, "geometry": { "type": "Point", "coordinates": [ 136.321249,-26.296000 ] }},
{ "type": "Feature", "properties": { "id": 96, "status": 0}, "geometry": { "type": "Point", "coordinates": [ 138.259022,-24.491771 ] }}]};


var width = 700,
    height = 700;

var proj = d3.geo.orthographic()
    .translate([width / 2, height / 2])
    .clipAngle(90)
    .scale(310);

var sky = d3.geo.orthographic()
    .translate([width / 2, height / 2])
    .clipAngle(90)
    .scale(360);

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

d3.select(window)
    .on("mousemove", mousemove)
    .on("mouseup", mouseup);


var svg = d3.select("body").select('.map').append("svg")
            .attr("width", width)
            .attr("height", height)
            .on("mousedown", mousedown)

queue()
    .defer(d3.json, "data/world-110m.json")   
    .await(ready);

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

function ready(error, world) {
  var globe_highlight = svg.append("defs").append("radialGradient")
        .attr("id", "globe_highlight")
        .attr("cx", "75%")
        .attr("cy", "25%");
      globe_highlight.append("stop")
        .attr("offset", "5%").attr("stop-color", "#ffd")
        .attr("stop-opacity","0.6");
      globe_highlight.append("stop")
        .attr("offset", "100%").attr("stop-color", "#ba9")
        .attr("stop-opacity","0.2");

  svg.append("circle")
    .attr("cx", width / 2).attr("cy", height / 2)
    .attr("r", proj.scale())
    .attr("class", "noclicks")
    .style("fill", "url(#ocean_fill)");

  svg.append("path")
    .datum(topojson.object(world, world.objects.land))
    .attr("class", "land noclicks")
    .attr("d", path);

  // POINTS
  svg.append("g").attr("class","points")
      .selectAll("text").data(places.features)
      .enter().append("path")
      .attr("class", "point")     
      .style("pointRadius", 2)
      .style("fill", "red");

  // CIRCLES
  svg.append("g").attr("class","circles")
      .selectAll("path").data(places.features)      
      .enter().append("circle")        
      .attr('cx', function(d) { return proj(d.geometry.coordinates)[0]})
      .attr('cy', function(d) { return proj(d.geometry.coordinates)[1]})    
      .attr("r", 4)   
      .style('fill', 'green')
      .attr("d", path);

  refresh();
}


function refresh() {

  // redraw land
  svg.selectAll(".land").attr("d", path);  

  // redraw circles
  svg.selectAll(".point").attr("d", path.projection(proj));

  // redraw circles
  svg.selectAll(".circles").attr("d", path.projection(proj));  

}


// modified from http://bl.ocks.org/1392560
var m0, o0;
function mousedown() {
  m0 = [d3.event.pageX, d3.event.pageY];
  o0 = proj.rotate();
  d3.event.preventDefault();
}

function mousemove() {
  if (m0) {
    var m1 = [d3.event.pageX, d3.event.pageY]
      , o1 = [o0[0] + (m1[0] - m0[0]) / 6, o0[1] + (m0[1] - m1[1]) / 6];
    o1[1] = o1[1] > 30  ? 30  :
            o1[1] < -30 ? -30 :
            o1[1];
    proj.rotate(o1);
    sky.rotate(o1);
    refresh();
  }
}

function mouseup() {
  if (m0) {
    mousemove();
    m0 = null;
  }
}
</script>
</html>

1 个答案:

答案 0 :(得分:2)

circle个元素没有d属性,只有path个元素。因此,您可能希望附加path而不是circle

此外,您要将课程分配给父g元素,因此refresh中的选择实际上是指g不是形状本身。您应该将类​​放在形状上,或者将选择更改为:

svg.selectAll(".point")
    .selectAll("path")
        .attr("d", path.projection(proj));