CSS d3.js Map (<svg>) 自动适应父容器并随窗口调整大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14265112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 21:17:01  来源:igfitidea点击:

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

csscanvassvgd3.js

提问by Jon

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 NON-WORKING code, but is not to be used as the solution.

更新:我已经在答案部分发布并接受了一个完全有效的解决方案。本节中的任何代码都将用作与您自己的非工作代码进行比较的参考,但不得用作解决方案。



I'm building a dashboard and using d3.js to add a world map that will plot tweets in real time based on geo location.

我正在构建一个仪表板并使用 d3.js 添加一个世界地图,该地图将根据地理位置实时绘制推文。

The world.jsonfile referenced in the d3.json() line is downloadable HERE(it's called world-countries.json).

d3.json() 行中引用的world.json文件可在此处下载(称为world-countries.json)。

enter image description here

在此处输入图片说明

The map is on the page as an SVG container and is rendered using d3.

地图作为 SVG 容器出现在页面上,并使用 d3 呈现。

Below are the relevant code slices.

下面是相关的代码片段。

<div id="mapContainer">
    <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="500"></svg>
</div>


#mapContainer svg {
    display:block;
    margin:0 auto;
}
#mapContainer path {
  fill:#DDD;
  stroke:#FFF;
}


// generate US plot
function draw() {
    var map = d3.select("svg");
    var width = $("svg").parent().width();
    var height = $("svg").parent().height();

    var projection = d3.geo.equirectangular().scale(185).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", height);
    });
}
draw();
latestLoop();


$(window).resize(function() {
    draw();
});

UPDATE: I have scaled the map to an acceptable size (for my particular browser size), but it still will not scale and center when I change the size of the window. IF, however, I resize the window, then hit refresh, then the map will be centered once the page is reloaded. However, since the scale is static, it is not scaled properly.

更新:我已将地图缩放到可接受的大小(对于我的特定浏览器大小),但是当我更改窗口大小时,它仍然无法缩放和居中。但是,如果我调整窗口大小,然后点击刷新,那么一旦页面重新加载,地图就会居中。但是,由于比例是静态的,因此无法正确缩放。

enter image description here

在此处输入图片说明

采纳答案by Jon

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);
});

回答by Spike Williams

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.

选择对象是一个多维数组,尽管在大多数情况下它可能只有一个对象。该对象有一个“clientWidth”字段,用于告诉您其父对象的宽度。

So you can do this:

所以你可以这样做:

var selection = d3.select("#chart"); 
width = selection[0][0].clientWidth;

回答by Elijah

This should work:

这应该有效:

<svg 
    xmlns="http://www.w3.org/2000/svg"
    width="860"
    height="500"
    viewBox="0 0 860 500"
    preserveAspectRatio="xMinYMin meet">

回答by Raj sree

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.

最好的选择是在 d3 图形的宽度和高度的正常定义上结合使用纵横比。这对我的很多图表工作都有帮助。
第 1 步:动态获取必须附加图形的 div 的高度。
第 2 步:将宽度声明为相对于动态捕获高度的纵横比。

var graph_div = document.getElementById(graph.divId);
graph.height = graph_div.clientHeight;
graph.width = (960/1200)*graph.height;

回答by Bimal Grg

In d3 v4, we could do this

在 d3 v4 中,我们可以这样做

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

fitSize is equivalent to

fitSize 相当于

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

fill free to add padding

自由填充以添加填充