d3.js Map (<svg>) 自动适应父容器并随窗口调整大小
Posted
技术标签:
【中文标题】d3.js Map (<svg>) 自动适应父容器并随窗口调整大小【英文标题】:d3.js Map (<svg>) Auto Fit into Parent Container and Resize with Window 【发布时间】:2012-12-25 06:21:19 【问题描述】:更新:我已在答案部分发布并接受了一个完全有效的解决方案。本节中的任何代码都将用作与您自己的 NON-WORKING 代码进行比较的参考,但不能用作解决方案。
我正在构建一个仪表板并使用 d3.js 添加一个世界地图,该地图将根据地理位置实时绘制推文。
d3.json() 行中引用的 world.json 文件是可下载的HERE(它被称为 world-countries.json)。
地图作为 SVG 容器在页面上,并使用 d3 呈现。
以下是相关的代码片段。
<div id="mapContainer">
<svg xmlns="http://www.w3.org/2000/svg" ></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();
);
更新:我已将地图缩放到可接受的大小(对于我的特定浏览器大小),但当我更改窗口大小时,它仍然不会缩放和居中。但是,如果我调整窗口大小,然后单击刷新,则重新加载页面后地图将居中。但是,由于比例是静态的,因此无法正确缩放。
【问题讨论】:
【参考方案1】:在 d3 v4 中,我们可以这样做
const projection = d3.geo.equirectangular().fitSize([width, height], geojson);
const path = d3.geo.path().projection(projection);
fitSize 等价于
fitExtent([[0, 0], [width, height]], geojson)
随意填充以添加内边距
【讨论】:
【参考方案2】:最好的选择是在正常定义d3图形的宽度和高度时结合使用纵横比。这对我的很多图表作品都有帮助。 第 1 步:动态获取图形必须附加到的 div 的高度。 第 2 步:将宽度声明为相对于动态捕获的高度的纵横比。
var graph_div = document.getElementById(graph.divId);
graph.height = graph_div.clientHeight;
graph.width = (960/1200)*graph.height;
【讨论】:
【参考方案3】:选择对象是一个多维数组,尽管在大多数情况下它可能只有一个对象。该对象有一个“clientWidth”字段,告诉您其父对象的宽度。
所以你可以这样做:
var selection = d3.select("#chart");
width = selection[0][0].clientWidth;
【讨论】:
由于我有一段时间没有看它,我会相信你的话。如果您有时间,小提琴可能会对未来的人有所帮助,但感谢您的回答! 使用d3v4,第二行应该是selection._groups[0][0].clientWidth
【参考方案4】:
完整的解决方案:
这是在用户释放窗口边缘以调整其大小并将其置于父容器中心之后调整地图大小的解决方案。
<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);
);
【讨论】:
这不是重写一切吗?我怎样才能避免这种情况? @arkanoid 也许......这个解决方案对我有用,所以如果它最终是这样做的,那么耸耸肩。我没有深入研究 d3 是如何渲染事物的,所以如果我的解决方案实际上只是重写,那么我想你就是这样做的。【参考方案5】:这应该可行:
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 860 500"
preserveAspectRatio="xMinYMin meet">
【讨论】:
所以这填充了容器,但是地图的缩放比例被放大了。有没有办法让它根据容器的大小进行缩放?我不在乎是否必须使用一些 jQuery 或 javascript,但我只是不知道我必须更改哪些值。 除了调整视图框的设置之外,您还想调整投影的 .scale() 。如果您有兴趣从地理空间角度显示更多或更少的地图,具体取决于您拥有多少屏幕空间,那么您将不想依赖 viewBox 方法,而是根据变化重新投影或旋转容器的宽度和高度。以上是关于d3.js Map (<svg>) 自动适应父容器并随窗口调整大小的主要内容,如果未能解决你的问题,请参考以下文章