如何调整 d3.js 地球仪的大小?

3

我想把这个地球仪的大小设置为200 x 200像素。

我知道目前这个投影的大小是960 x 500像素。

改变SVG的大小并不能缩小地球仪。我不太明白为什么。

尝试在代码中添加以下内容,但没有成功:

var width = 200;
var height = 200;

并且

const width = 200;
const height = 200;

并且

const svg = d3.select('svg')
.attr('width', 200).attr('height', 200);

我应该如何最好地解决这个问题,我做错了什么?

我的代码:

<!DOCTYPE html>
<html>
    <body>
        <svg></svg>
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <script src="https://d3js.org/topojson.v1.min.js"></script>
        <script>
            const width = 960;
            const height = 500;
            const config = {
              speed: 0.005,
              verticalTilt: -20,
              horizontalTilt: 0
            }
            let locations = [];
            const svg = d3.select('svg')
                .attr('width', width).attr('height', height);
            const markerGroup = svg.append('g');
            const projection = d3.geoOrthographic();
            const initialScale = projection.scale();
            const path = d3.geoPath().projection(projection);
            const center = [width/2, height/2];

            drawGlobe();    
            drawGraticule();
            enableRotation();    

            function drawGlobe() {  
                d3.queue()
                    .defer(d3.json, 'world-110m.json')          
                    .defer(d3.json, 'locations.json')
                    .await((error, worldData, locationData) => {
                        svg.selectAll(".segment")
                            .data(topojson.feature(worldData, worldData.objects.countries).features)
                            .enter().append("path")
                            .attr("class", "segment")
                            .attr("d", path)
                            .style("stroke", "silver")
                            .style("stroke-width", "1px")
                            .style("fill", (d, i) => 'silver')
                            .style("opacity", ".5");
                            locations = locationData;
                            drawMarkers();                   
                    });
            }

            function drawGraticule() {
                const graticule = d3.geoGraticule()
                    .step([10, 10]);

                svg.append("path")
                    .datum(graticule)
                    .attr("class", "graticule")
                    .attr("d", path)
                    .style("fill", "#fff")
                    .style("stroke", "#ececec");
            }

            function enableRotation() {
                d3.timer(function (elapsed) {
                    projection.rotate([config.speed * elapsed - 120, config.verticalTilt, config.horizontalTilt]);
                    svg.selectAll("path").attr("d", path);
                    drawMarkers();
                });
            }        

            function drawMarkers() {
                const markers = markerGroup.selectAll('circle')
                    .data(locations);
                markers
                    .enter()
                    .append('circle')
                    .merge(markers)
                    .attr('cx', d => projection([d.longitude, d.latitude])[0])
                    .attr('cy', d => projection([d.longitude, d.latitude])[1])
                    .attr('fill', d => {
                        const coordinate = [d.longitude, d.latitude];
                        gdistance = d3.geoDistance(coordinate, projection.invert(center));
                        return gdistance > 1.57 ? 'none' : 'tomato';
                    })
                    .attr('r', 7);

                markerGroup.each(function () {
                    this.parentNode.appendChild(this);
                });
            }
        </script>
    </body>
</html>
1个回答

4

投影.scale()

投影的比例尺决定了投影世界的大小。一般来说,d3 投影具有默认的比例尺值,该值将填充一个 960x500 的 SVG/Canvas。使用 d3.geoOrthographic 创建的地图没有长边,因此它是 500x500 像素。默认比例尺值为:249.5 - 半个宽度/高度(考虑描边宽度)。这个比例因子对宽度和高度都是线性的:将其加倍并将两者都加倍(将投影后的世界大小增加到四倍)。因此,如果您希望有一个 200x200 像素的世界,则需要使用 99.5 作为您的比例尺值。

这是 d3.geoOrthographic 的默认设置,其他比例尺有其他默认设置。例如,对于墨卡托投影,它是 480 / π:横跨 960 像素宽度的 2π 经度。

投影.translate()

然而,如果您更改了一个 200x200 像素世界的比例尺,您将会遇到默认投影平移的问题。默认情况下,它设置为 [250,480] - 默认 D3 预期的 SVG/Canvas 的一半 [500,960]。这个坐标是投影中心(默认为 0°N,0°W)的投影位置。您需要将其更改为值 [100,100]:SVG/Canvas 的中心。

解决方案

const projection = d3.geoOrthographic()
  .scale(99.5)
  .translate([100,100]);

自动化解决方案

有一种更简单的方法,但了解机制也是有用的。

projection.fitSize()/.fitExtent() 可以根据指定的宽度/高度或范围自动设置比例尺和平移。在您的情况下,手动解决问题很容易,但您也可以使用:

 d3.geoOrthographic()
   .fitSize([width,height],geoJsonObject)


 d3.geoOrthographic()
   .fitExtent([[left,top],[right,bottom]],geojsonObject)

在使用topojson时:topojson.feature会返回一个geojson对象(具有包含单个要素的features属性-不能将要素数组传递给fitSize或fitExtent)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接