难以理解的无法在d3.js地图上呈现城市名称标签:超出范围NAME?

时间:2016-06-12 20:03:50

标签: javascript json d3.js

我正在遵循规范的“Let’s Make a Map”教程 - 但为了增加趣味我将其与one about Germany融合 - 所以我正在使用略有不同的数据。

到目前为止,事情已经完成 - barring this minor hiccup - 但现在我来到了“#Displaying Places”这一部分,你应该在地图上显示城市的名字。

问题出现在以下几行:

   .text(function(d) {
        if (d.properties.name!=="Berlin" &&
            d.properties.name!=="Bremen"){

                //for some reason this is undefined
                console.log(d.properties.name);
                return d.properties.name;
        }
    })

console.log(d.properties.name);的值总是未定义的,我无法找出原因!

我想这是因为name超出了d的范围 - 但我不知道如何修复它。 是吗?如果是这样 - 如何解决它?如果不是 - 真正的问题是什么?

这是我的代码看起来像 - 它非常简洁:

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

.subunit{fill:#fff;}
.subunit.Nordrhein-Westfalen{ fill: #aba; }
.subunit.Baden-Württemberg{ fill: #bab; }
.subunit.Hessen{ fill: #bcb; }
.subunit.Niedersachsen{ fill: #cbc; }
.subunit.Thüringen{ fill: #cdc; }
.subunit.Hamburg{ fill: #dcd; }
.subunit.Schleswig-Holstein{ fill: #ded; }
.subunit.Rheinland-Pfalz{ fill: #ede; }
.subunit.Saarland{ fill: #efe; }
.subunit.Sachsen-Anhalt{ fill: #fef; }
.subunit.Brandenburg{ fill: #aaa; }
.subunit.Mecklenburg-Vorpommern{ fill: #bbb; }
.subunit.Bayern { fill: #ccc; }
.subunit.Sachsen { fill: #ddd; }
.subunit.Bremen { fill: #eee; }
.subunit.Berlin { fill: #fff; }

.subunit-boundary {
  fill: none;
  stroke: #777;
  stroke-dasharray: 2,2;
  stroke-linejoin: round;
}


.place,
.place-label {
  fill: #444;
  font-size:14px;
}

text {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 20px;
  pointer-events: none;
}


</style>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>

var width = 960,
    height = 1160;

var projection = d3.geo.mercator()
    .center([10.5, 51.35])
    .scale(3000)
    .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("de.json", function(error, de) {

    //colouring the different subunits
    svg.selectAll(".subunit")
       .data(topojson.feature(de, de.objects.subunits).features)
       .enter().append("path")
       .attr("class", function(d) {
        // console.log(d.properties.name);
        return "subunit " + d.properties.name;
       })
       .attr("d", path);

    //adding a border to the states
    svg.append("path")
        .datum(topojson.mesh(de, de.objects.subunits, function(a,b) {
            if (a!==b ||
                a.properties.name === "Berlin"||
                a.properties.name === "Bremen"){
                    var ret = a;
                }
                    return ret;
                }))
        .attr("d", path)
        .attr("class", "subunit-boundary");

    // add small black dots for populated places
    svg.append("path")
       .datum(topojson.feature(de, de.objects.places))
       .attr("d", path)
       .attr("class", "place");



    //trying to display names of cities
    svg.selectAll(".place-label")
       .data(topojson.feature(de, de.objects.places).features)
       .enter().append("text")
       .attr("class", "place-label")
       .attr("transform", function(d) {

            //small test
            //console.log( "translate(" + projection(d.geometry.coordinates) + ")" );

            return "translate(" + projection(d.geometry.coordinates) + ")";
        })
       .attr("dy", ".35em")
       .text(function(d) {
            if (d.properties.name!=="Berlin" &&
                d.properties.name!=="Bremen"){

                    //for some reason this is undefined
                    console.log(d.properties.name);
                    return d.properties.name;
            }
        })
       .attr("x", function(d) {
            return d.geometry.coordinates[0] > -1 ? 6 : -6;
        })
       .style("text-anchor", function(d) {
            return d.geometry.coordinates[0] > -1 ? "start" : "end";
       });



});

</script>

Here is the data file

修改

预期

enter image description here

实际

enter image description here

2 个答案:

答案 0 :(得分:4)

在.topojson中你有两个部分:

  • 属性:您的县和多边形的名称
  • 地点:点的坐标

您可以通过以下方式访问第一个集合:

de.objects.subunits

第二个收集通过:

de.subunits.places

将文件加载到两个不同的变量后使用它:

d3.json("de.json", function(error, de) {
    var counti = topojson.feature(de, de.objects.subunits)
    var places = topojson.feature(de, de.objects.places)

然后引用内容添加.features

   .data(counti.features)   // <-- to draw your paths and get the .name: München

   .data(places.features)  // <-- to draw the circles for the cities: "coordinates": [11.573039376427117, 48.131688134368815]

Mike的topojson有:

{
  "type": "Feature",
  "properties": {
    "name": "Ayr"
  },
  "geometry": {
    "type": "Point",
    "coordinates": [
      -4.617021378468872,
      55.44930882146421
    ]
  }

你有:

 {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Point",
    "coordinates": [
      11.573039376427117,
      48.131688134368815
    ]
  }

Mike的点属性如下所示:

enter image description here

和点坐标

enter image description here

您的观点属性:

enter image description here

解决方案:

正确的方式

  • 在GIS软件上打开地图(ArcGIS-pay,无Q-GIS)编辑并更正路径和点属性,然后再次导出为TopoJSON .-

简单方法

  • 转到:geojson.io加载你的json并为你的点添加属性名称(16分,简单蛋糕)并再次保存为TopoJSON .-

enter image description here

现在您正确删除了一列(您有重复的信息)

enter image description here

答案 1 :(得分:1)

@Klaujesi很好地解释了原因。

我只是想解决这个问题。

由于功能内部没有属性,因此您可以从de.objects.subunits获取属性,如下所示。

.text(function(d, i) {
//here i is the index of the place.
//de.objects.subunits.geometries[i].properties will give you the name that you are looking for.
            d.properties = de.objects.subunits.geometries[i].properties;
            if (d.properties.name!=="Berlin" &&
                d.properties.name!=="Bremen"){

                    //for some reason this is undefined
                    console.log(d);
                    return d.properties.name;
            }
        })

工作代码here