D3地图显示国家名称

时间:2015-10-19 11:19:23

标签: javascript d3.js svg topojson

我正在尝试创建一个显示所有国家/地区名称的d3地图。

这个地球仪: globe map

当我尝试展示这些国家时,地球会变成这个烂摊子: mess globe

var app = angular.module("myapp", []);

    app.directive("globe", function() {
        return {
            restrict   : 'E',
            scope      : {
                data: '=?'
            },
            template: 
            '<div class="globe-wrapper">' +
                '<div class="globe"></div>' +
                '<div class="info"></div>' +
            '</div>',
            link: link
        };
        
        function link(scope, element, attrs) {
            var width = 500, height = width, 
                projection, path,
                svg, features, graticule,
                mapJson = 'https://gist.githubusercontent.com/GordyD/49654901b07cb764c34f/raw/27eff6687f677c984a11f25977adaa4b9332a2a9/countries-and-states.json',
                states, stateSet, countries, countrySet, zoom;
            
            projection = d3.geo.orthographic()
                .translate([width / 2, height / 2])
                .scale(250)
                .clipAngle(90)
                .precision(0.1)
                .rotate([0, -30]);
            
            path = d3.geo.path()
                .projection(projection);
            
            svg = d3.select(element[0]).select('.globe')
                .append('svg')
                .attr('width', width)
                .attr('height', height)
                .attr('viewBox', '0, 0, ' + width + ', ' + height);
           
            features = svg.append('g');
            
            features.append('path')
                .datum({type: 'Sphere'})
                .attr('class', 'background')
                .attr('d', path);
            
            graticule = d3.geo.graticule();

            features.append('path')
              .datum(graticule)
              .attr('class', 'graticule')
              .attr('d', path);
            
            zoom = d3.geo.zoom()
              .projection(projection)
              .scaleExtent([projection.scale() * 0.7, projection.scale() * 8])
              .on('zoom.redraw', function(){
                d3.event.sourceEvent.preventDefault();
                svg.selectAll('path').attr('d',path);
              });
            
            d3.json(mapJson, function(error, world) {
                states = topojson.feature(world, world.objects.states).features;
                countries = topojson.feature(world, world.objects.countries).features;
                
                stateSet = drawFeatureSet('state', states);
                countrySet = drawFeatureSet('country', countries);
                
                d3.selectAll('path').call(zoom);
            });
            
            function drawFeatureSet(className, featureSet) {
                var set  = features.selectAll('.' + className)
                .data(featureSet)
                .enter()
                .append('g')
                .attr('class', className)
                .attr('data-name', function(d) {
                    return d.properties.name;
                })
                .attr('data-id', function(d) {
                    return d.id;
                });
                
                set.append("text")
                        .attr("class", "country-label")
                        .attr("transform", function(d) { console.log("d", d); return "translate(" + 	      path.centroid(d) + ")"; })
                        .text(function(d) { return d.properties.name; })
                        .attr("x", function(d){
                            return path.centroid(d)[0];
                        })
                        .attr("y", function(d){
                            return  path.centroid(d)[1];
                        });
                
                set.append('path')
                .attr('class', 'land')
                .attr('d', path);
                
                set.append('path')
                .attr('class', 'overlay')
                .attr('d', path)
                .attr('style', function(d) {
                    if (scope.data[d.id]) {
                        return 'fill-opacity: ' + (scope.data[d.id]/100);
                    }
                })
                .on('click', function(d) {
                    var val = (scope.data[d.id]) ? scope.data[d.id] : 0;
                    d3.select(element[0]).select('.info').html(d.properties.name + ': ' + val);
                    
                    rotateToFocusOn(d);
                }); 
                
                return set;
            }
            
            function rotateToFocusOn(x) {
                var coords = d3.geo.centroid(x);
                coords[0] = -coords[0];
                coords[1] = -coords[1];
                
                d3.transition()
                .duration(1250)
                .tween('rotate', function() {
                    var r = d3.interpolate(projection.rotate(), coords);
                    return function(t) {
                        projection.rotate(r(t));
                        svg.selectAll('path').attr('d', path);
                    };
                })
                .transition();
            }
        }
    });

    app.controller("ctrl1",function($scope, $log) {
        $scope.data = {};
    });

    app.run();
svg {
    width: 100%
}

path {
    fill: none;
    stroke: black
}

.background {
  fill: rgba(200,212,220,.5);
  stroke-width: .8px;
  stroke: black;
}

.graticule {
    stroke: rgba(0,0,0, .2);
    stroke-width: .5px;
}

.country {
    cursor: pointer;
}

.country .land, .state .land {
    fill: white;
    stroke: rgba(0,0,0, .2);
    stroke-width .3px;
}

.state .overlay {
    fill: blue;
    fill-opacity: 0;
}

.country .overlay {
    fill: orange;
    fill-opacity: 0;
}

.country-label {
    fill: #777;
    fill-opacity: .5;
    font-size: 20px;
    font-weight: 300;
    text-anchor: middle;
}
<script src="https://www.workshape.io/js/geo/d3.geo.zoom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div ng-app="myapp">
    <div ng-controller="ctrl1">
        <globe data="data"></globe>
    </div>
</div>

任何人都知道如何显示这些国家/地区的国家名称? 除了不在一起之外,在旋转地球时,名称会改变地点。

1 个答案:

答案 0 :(得分:0)

试试这种方式

                set.append("text")
                        .attr("class", "country-label")
                        .attr("transform", function(d) { console.log("d", d); return "translate(" +           path.centroid(d) + ")"; })
                        .text(function(d) { return d.properties.name; })
                        .attr("dx", function (d) {
                        return "0.3em";

                    })
                    .attr("dy", function (d) {
                        return "0.35em";
                    })
                    .style('fill', 'black');