D3js cartography: auto-focus on geographic area ? (svg canvas, zoom scale, coordinate translation)

后端 未结 1 530
难免孤独
难免孤独 2021-01-07 13:53

I processed SRTM raster data to generate shapefiles -> geojson -> topojson so I may feed D3js with a suitable format.

The result look like this (the blue area is my

相关标签:
1条回答
  • 2021-01-07 14:22

    I reused some code from Bostock & al, with some edits so you input your focus geo-area bounds (decimal coordinates):

    var WNES = { "W": 67.0, "N":37.5, "E": 99.0, "S": 5.0 };
    

    and the target svg canvas' width (px) such :

    var width  = 600,
    

    to automatically set the svg canvas' height, the zoom scale, and the translation in order to focus the display only on and fully on the target geo area.

    // 1. -------------- SETTINGS ------------- //
    // India geo-frame borders (decimal ⁰)
    var WNES = { "W": 67.0, "N":37.5, "E": 99.0, "S": 5.0 };
    // Geo values of interest :
    var latCenter = (WNES.S + WNES.N)/2, // will not be used
        lonCenter = (WNES.W + WNES.E)/2, // will not be used
        geo_width = (WNES.E - WNES.W),
        geo_height= (WNES.N - WNES.S);
    // HTML expected frame dimensions
    var width  = 600,
        height = (geo_height / geo_width) * width ; // height function of width with ratio of geo-frame (later requires equirectangular projection!)
    
    // Projection: projection, reset scale and reset translate
    var projection = d3.geo.equirectangular()
          .scale(1)
          .translate([0, 0]);
    
    // Normal stuff: SVG injection:
    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height);
    
    // Normal stuff: Path
    var path = d3.geo.path()
        .projection(projection)
        .pointRadius(4);
    
    // Data (getJSON: TopoJSON)
    d3.json("final.json", showData);
    
    // 2. ---------- FUNCTION ------------- //
    function showData(error, fra) {
        var Levels = topojson.feature(fra, fra.objects.levels);
    
    // Focus area box compute to derive scale & translate.
    var b = path.bounds(Levels), // get data's bounds as [​[left, bottom], [right, top]​]  [[W, S], [E, N]]
        s = 1 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
        t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
    
    // Projection update
    projection
        .scale(s)
        .translate(t);
    
    //Normal stuff: Append my topojson objects => svg layers
        svg.append("path")
            .datum(Levels)
            .attr("d", path)
        svg.selectAll(".levels")
            .data(topojson.feature(fra, fra.objects.levels).features)
          .enter().append("path")
            .attr("class", function(d) { return "Topo_" + d.properties.name; })
            .attr("data-elev", function(d) { return d.properties.name; })
            .attr("d", path)
    }
    

    Result is perfect:

    enter image description here

    See:

    • path.bounds(feature) -- Computes the projected bounding box (in pixels) for the specified feature.

    • India relief map with auto-focus (Hugo Lopez) -- Working example (with custom canvas height)

    • Center a map in d3 given a geoJSON object (Bostock & al.) -- critical help from there

    • Project to Bounding Box (Mike Bostock) -- Working example (with prefixed canvas dimensions)

    • D3js: How to design topographic maps? (Hugo Lopez) -- tutorial with makefile and html-d3js code.

    0 讨论(0)
提交回复
热议问题