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

问题描述

我正在尝试将this globe的大小设置为200 x 200px。

我了解到该投影的当前尺寸为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.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>

解决方法

Projection.scale()

投影的比例决定了投影世界的大小。一般来说,d3投影具有默认的比例值,该比例值将填充960x500 SVG /画布。使用d3.geoOrthographic生成的地图没有长边,因此为500x500像素。默认比例值是:249.5-宽度/高度的一半(允许笔触宽度)。此比例因子在宽度和高度上都是线性的:将其加倍,并将其加倍(世界投影尺寸的四倍)。因此,如果您想要200x200像素的世界,则需要:99.5作为比例值。

这是d3.geoOrthographic的默认设置,其他比例尺具有其他比例尺默认值。例如,对于墨卡托来说,它是480 /π:在960像素宽度上的经度为2π。

Projection.translate()

但是,如果您更改200x200像素世界的比例,则默认投影转换会出现问题。默认情况下,此值设置为[250,480]-[500,960]的一半,即SVG /画布的默认D3预期大小。此坐标是投影地理中心(默认为0°N,0°W)的投影位置。您需要将此值更改为[100,100]:SVG /画布的中心。

解决方案

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)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...