如何使用d3创建响应式地图

时间:2014-01-02 14:30:35

标签: d3.js

我试图让我的地图响应,因此可以根据浏览器窗口大小调整其大小。这是我到目前为止所做的,

的style.css

#mapbox {
border:2px solid #000;
width:960px;
height:550px;
background:#FFFFFF;
}

viz.js

var margin = {top: 10, left: 10, bottom: 10, right: 10},
width = parseInt(d3.select('#mapbox').style('width')), 
width = width - margin.left - margin.right, 
mapRatio = .5, 
height = width * mapRatio;
.
.
d3.select(window).on('resize', resize);
.
.
function resize(){  
    width = parseInt(d3.select('#mapbox').style('width'));
    width = width - margin.left - margin.right;
    height = width * mapRatio;


        projection.translate([width / 2, height / 2])
                .scale(width);

        svg.style('width', width + 'px')
            .style('height', height + 'px');

}

当我调整窗口大小时,它仍保持与svg容器相同的宽度和高度。我想这是因为,在调整大小功能时,我是否从CSS中获取宽度和高度,无论我调整窗口大小都是正确的?

我被困在这里,我错过了什么明显的东西?如果你有任何指示让我开始工作,那将会很棒。

我几乎遵循以下example

3 个答案:

答案 0 :(得分:3)

我将svg设置为响应调整大小:

var svg = d3.select("body")
        .append("div")
        .attr("id", "svg")
        .append("svg")
        .attr("viewBox", "0 0 " + width + " " + height )
        .attr("preserveAspectRatio", "xMinYMin");

然后像这样设置css:

#svg {
    width:100%;
    height: auto;
}

答案 1 :(得分:1)

感谢指点,

这对我有用,但不确定这是否是最佳做法。

HTML

     <section id = "mapContainer">
        <svg id = "map" width="960" height="550"
            viewBox="0 0 960 550"   preserveAspectRatio="xMidYMid"> 
        </svg>
     </section>

的Javascript

    var svgContainer = $("#map");
    var width = svgContainer.width();
    var height = svgContainer.height();
    var aspect = width/height;
    var container = svgContainer.parent();

    var svg = d3.select("svg");

    //responsive map
function resize(){
    // adjust things when the window size changes
    var targetWidth = container.width();

    svg.attr("width", targetWidth);
    svg.attr("height", Math.round(targetWidth/aspect));

    console.log ("width : " + targetWidth);
    console.log ("height : " + Math.round(targetWidth/aspect));

    // update projection
    projection.translate([width / 2, height / 2])
                .scale(width);

    // resize the map
        svg.select('.lga').attr('d', path);
}

答案 2 :(得分:0)

在你的问题中没有足够的细节来准确地说出你在做什么。有一些常见的东西可以打破这样的调整大小代码...

您的地图集可能不会改变大小。您可以使用每个调用的宽度/高度调整一个console.log(...)来调整大小,并且会告诉您到底发生了什么。

此外,根据您最初如何指定SVG的大小(例如,使用宽度/高度属性与使用高度/宽度css设置),您可以创建一个冲突,其中属性大小规范优先于css。

如果您的宽度/高度值被错误地解析并且随后被错误地设置,那么它将忽略那些CSS设置并且大小永远不会改变。

最后,如果您阅读了Lars链接的SO,您会发现使用viewbox / preserveaspectration方法进行svg缩放的更简单方法。这是我在为我的东西工作时所做的一个小提琴:http://jsfiddle.net/reblace/Ku2UQ/2/

var svg = container.selectAll("svg").data([data]);
var svgEnter = svg.enter().append("svg");

// Append a clip path that will hide any data points outside of the xExtent and yExtent
svgEnter
    .attr("viewBox", "0 0 600 200") // This is the "ideal" size of the chart
    .attr("preserveAspectRatio", "xMinYMin");

...

var resize = function(w, h){
    svg.transition().duration(500)
        .attr("width", w)
        .attr("height", w / (width/height));        
};

function doResize() {
    var overflow = $("body").css("overflow");
    $("body").css("overflow", "hidden");

    var width = $("#center").innerWidth();
    var height = $(window).innerHeight() - 10;

    $("body").css("overflow", overflow);
    resize(width, height);
};

var resizeTimer;
$(window).resize(function() {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(doResize, 250);
});

doResize();

这段代码做了一些值得关注的事情,包括过滤resize事件,以便它不会为窗口的每个像素大小更改调用resize代码。相反,它基本上缓冲了事件,直到你停止调整窗口大小250ms。

然后,它会隐藏页面上的滚动条,这样,如果您尝试在没有滚动条的情况下缩放页面以适应页面,则可以获得准确的窗口大小。

最后,它会缩放SVG元素,该元素处理调整内容的大小并根据父容器的大小将其设置为正确的大小(根据原始宽度/高度比例缩放高度。