【问题标题】:How to center and scale using geoPath如何使用 geoPath 居中和缩放
【发布时间】:2023-07-20 20:52:01
【问题描述】:

我正在使用 D3 和 topojson 过滤掉一部分美国县。我可以成功过滤出县并将它们绘制到 SVG 元素,但是如何更改地图边界以适应新选择的县?它将地图渲染为边界是所有美国县,而不是仅过滤的县。

    var width=960,
        height=600,
        centered;

    const svgElement = d3.select(ref.current)
        .append("svg")
        .attr("preserveAspectRatio", "xMinYMin meet")
        .attr("viewBox", [0,0,width,height]);

    var path = d3.geoPath();
    d3.json("https://d3js.org/us-10m.v2.json").then((d) => {
        d.objects.counties.geometries = d.objects.counties.geometries.filter(function(item) {
            return props.data.indexOf(item.id) > -1
        })
        var counties = topojson.feature(d, d.objects.counties).features;
        svgElement.append("g")
            .attr("class", "filled-territory")
            .selectAll("path")
            .data(counties) 
            .enter()
            .append("path")
            .attr("d", path)
        });

props.data 是一个县 ID 数组,例如 -

[
    "45001",
    "45003",
    "45007",
    "45083",
    "45087",
    "45091"
]

我可以让它像这样显示,但我不知道如何让路径填充 SVG:

【问题讨论】:

    标签: javascript d3.js topojson


    【解决方案1】:

    此特定文件使用像素坐标系(它是投影的地理数据),它填充 [0,0] 到 [960,600] 之间的范围。因为它使用这个坐标系,所以我们通常可以使用 d3.geoPath 的默认投影,一个将你的 json 中的坐标视为像素的空投影。但是,geoPath 本身并不能提供一种使您的特征居中或缩放的方法。

    D3 地理投影带有一个名为 fitSize(也称为 fitExtent 或其他)的方法,该方法采用 geojson object 并设置投影比例并转换属性以使该 geojson 对象在指定范围内居中。由于我们已经有了投影数据,我们可以使用 d3.geoIdentity(),它提供了一些方便的投影方法,例如 fitSize,但不会投影我们已经投影的数据。

    为了使用 fitSize,我们可以使用以下内容:

       // get a geojson feature collection object:
       var geojson = topojson.feature(d, d.objects.counties)
    
       // create a geoidentity "projection" and center the geojson:            
       var projection = d3.geoIdentity()
               .fitSize([width,height],geojson)
               
       // set the path's projection:
       path.projection(projection);
            
       // Now access the array of features in the collection for use with .data():
       var counties = geojson.features;
    

    看起来像:

    var data = [
        "45001",
        "45003",
        "45007",
        "45083",
        "45087",
        "45091"
    ]
    
    var width=500,
        height=500;
    
    const svgElement = d3.select("body")
            .append("svg")
            .attr("width", width)
            .attr("height", height);
    
    var path = d3.geoPath();
       
    d3.json("https://d3js.org/us-10m.v2.json").then((d) => {
            d.objects.counties.geometries = d.objects.counties.geometries.filter(function(item) {
                return data.indexOf(item.id) > -1
            })
            
            
            var geojson = topojson.feature(d, d.objects.counties)
            
            var projection = d3.geoIdentity()
               .fitSize([width,height],geojson)
               
            path.projection(projection);
            
            var counties = geojson.features;
            
            svgElement.append("g")
                .attr("class", "filled-territory")
                .selectAll("path")
                .data(counties) 
                .enter()
                .append("path")
                .attr("d", path)
            });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js
    "></script>

    【讨论】:

      最近更新 更多