d3.js Map (<svg>) Auto Fit into Parent Container and Resize with Window

前端 未结 5 2115
时光取名叫无心
时光取名叫无心 2020-12-23 16:54

UPDATE: I have posted and accepted a fully working solution in the answers section. Any code in this section is to be used as reference for comparison to your own NO

相关标签:
5条回答
  • 2020-12-23 17:33

    The best choice is to have a combined use of aspect ratio on normal definition of d3 graph's width and height. This has helped me in lot of my graph works.
    Step 1 : Dynamically get the height of the div to which the graph has to be appended.
    Step 2 : Declare width as aspect ratio with respect to the dynamically caught height.

    var graph_div = document.getElementById(graph.divId);
    graph.height = graph_div.clientHeight;
    graph.width = (960/1200)*graph.height;
    
    0 讨论(0)
  • 2020-12-23 17:34

    The selection object is an multidimensional array, although in most cases it will probably have only one object in it. That object has a "clientWidth" field that tells you how wide its parent is.

    So you can do this:

    var selection = d3.select("#chart"); 
    width = selection[0][0].clientWidth;
    
    0 讨论(0)
  • 2020-12-23 17:36

    This should work:

    <svg 
        xmlns="http://www.w3.org/2000/svg"
        width="860"
        height="500"
        viewBox="0 0 860 500"
        preserveAspectRatio="xMinYMin meet">
    
    0 讨论(0)
  • 2020-12-23 17:37

    COMPLETE SOLUTION:

    Here's the solution which will resize the map AFTER the user has released the edge of the window to resize it, and center it in the parent container.

    <div id="mapContainer"></div>
    

    function draw(ht) {
        $("#mapContainer").html("<svg id='map' xmlns='http://www.w3.org/2000/svg' width='100%' height='" + ht + "'></svg>");
        map = d3.select("svg");
        var width = $("svg").parent().width();
        var height = ht;
    
        // I discovered that the unscaled equirectangular map is 640x360. Thus, we
        // should scale our map accordingly. Depending on the width ratio of the new
        // container, the scale will be this ratio * 100. You could also use the height 
        // instead. The aspect ratio of an equirectangular map is 2:1, so that's why
        // our height is half of our width.
    
        projection = d3.geo.equirectangular().scale((width/640)*100).translate([width/2, height/2]);
        var path = d3.geo.path().projection(projection);
        d3.json('plugins/maps/world.json', function(collection) {
            map.selectAll('path').data(collection.features).enter()
                .append('path')
                .attr('d', path)
                .attr("width", width)
                .attr("height", width/2);
        });
    }
    draw($("#mapContainer").width()/2);
    

    $(window).resize(function() {
        if(this.resizeTO) clearTimeout(this.resizeTO);
        this.resizeTO = setTimeout(function() {
            $(this).trigger('resizeEnd');
        }, 500);
    });
    
    $(window).bind('resizeEnd', function() {
        var height = $("#mapContainer").width()/2;
        $("#mapContainer svg").css("height", height);
        draw(height);
    });
    
    0 讨论(0)
  • 2020-12-23 17:38

    In d3 v4, we could do this

    const projection = d3.geo.equirectangular().fitSize([width, height], geojson);
    const path = d3.geo.path().projection(projection);
    

    fitSize is equivalent to

    fitExtent([[0, 0], [width, height]], geojson)
    

    fill free to add padding

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