d3.js svg从(geo / topo)json绘制轮廓线

时间:2014-04-05 03:06:01

标签: json svg d3.js geojson topojson

我正在寻找关于如何根据来自(geo / topo)JSON的轮廓线数据创建由路径组成的SVG图像的一些指导,并使用d3.js进行渲染。

这是我想要创建的图像: Example of final product. (Note: the colors are not true to the contours in the example, this is just from photoshop)

最终,我希望图像能够响应缩放,动画(绘制线条,交互式地改变颜色)路径,并能够交换出不同的数据文件来渲染其他图像。

我已经浏览了几个指南,教程等,但是到目前为止我似乎缺少一些步骤或执行错误的程序,所以我想我会问这里。谢谢你的帮助。

我正在努力澄清这样做的最佳方法,并弄清楚我在d3.js中的功能/程序方面的误解。

我通过在QGIS中提取轮廓来从DEM(数字高程模型)数据创建轮廓线。为了从这些中获取JSON,我尝试在QGIS中保存为GeoJSON,并在OGR2OGR中将Shapefile(ESRI .shp)转换为GeoJSON。我也尝试过使用Node的Topojson(https://www.npmjs.org/package/topojson)。在大多数情况下,我已经能够获得JSON文件,虽然我转换它们的方式可能有问题,或者来自QGIS的原始轮廓数据使得它与我在d3中尝试的不兼容

我在JSON渲染时获得的结果基本上看起来像黑盒子(看起来像svg容器内部不正确渲染的多边形)。如果我将填充颜色更改为无,我会看到疯狂的线条。我在某处读到TopoJSON必须是多边形而不是直线或折线,因为它使用弧线,但我使用GeoJSON获得了相同的结果。

我想知道这是否与我从QGIS导出轮廓线并转换为JSON的方式有问题,或许预测不排队?在转换时自动创建的行中也可能存在一些错误,但我不确定如何解决这些问题。正如您在示例图像中看到的,我的一些轮廓不是闭环,因为它们超出了我有/想要显示数据的区域的边界。这些应该被渲染为折线或路径是否有意义?

另外请注意,我对这些项目的“地理位置”在这个项目的纬度或地理位置方面并不特别感兴趣。基本上只使用来自真实地理数据的轮廓线来显示线条图案。

这是我的代码:

<script type="text/javascript">
var width = 500,
    height = 500;

var svg = d3.select("#section-1-svg").append("svg")
    .attr("width", width)
    .attr("height", height);

d3.json("contour.json", function(error, contour) {
    console.log(contour);
});

var path = d3.geo.path()
    .projection(d3.geo.mercator());

    d3.json("contour.json", function(error, json) {

    svg.selectAll("path")
        .data(json.features)
        .enter()
        .append("path")
        .attr("d", path);
});
</script>

除了让它在基本级别上呈现之外,其他问题是: 我是否可以选择单独的线条进行动画处理,例如stroke-dashoffset? 此源JSON是否仍包含高程数据,因此我可以根据高程对行进行着色?

感谢您帮助我实现这一目标!我很感激任何人为我澄清这一点,并通知我最好的方式来呈现这一点。

编辑:使用user1614080示例中的代码,我正在渲染这些行:

    svg.selectAll("path")
    .data(topo).enter()
    .append("path")
    .style("fill", "none")
    .style("stroke", function(d, i) {
        return interp(cScale(d.properties.ELEV));
    })
.attr("d", path)
.each(function(d) {
    d.totalLength = this.getTotalLength();
    console.log(d.totalLength);

})
.attr("stroke-dasharray", function(d) { return d.totalLength + " " + d.totalLength;})
.attr("stroke-dashoffset", function(d) { return d.totalLength; })
.transition()
    .delay(function(d, i) { return i * 200; })
    .duration(4000)
    .ease("linear")
    .attr("stroke-dashoffset", "0");
    });

但我无法得到我需要的效果(画线)。它们似乎从小破折号中淡出而不是画出整个破折号。我可以在浏览器中看到正确分配了stroke-dasharray和offset,只是无法弄清楚为什么不遵循转换。

1 个答案:

答案 0 :(得分:3)

继Lar提到的之后,我真的看不出你到底有什么问题(除了你是两个相同的d3.json电话,但这不应该导致你的问题)。

您描述的工作流程或多或少与我之前所做的相同。我能想到的唯一可能导致你麻烦的事情(虽然不是你提供的代码)是topojson的默认设置不保留功能属性而你必须使用-p开关。

无论如何,我已经意味着暂时做一个轮廓示例,这似乎是一个很好的机会所以我创建了一个你可以看到here的机会。代码和自述文件中有相当多的解释,所以我希望这可以帮助你。

一旦你开始工作,你就可以创建各种各样的交互等。例如在我的例子中,你可以使用类似下面的内容突出显示鼠标悬停事件的轮廓:

.on("mouseover", highlight)
.on("mouseout", unhighlight(this, d)

function highlight(x) {
    var s = d3.select(this);
    s.style("stroke", "red");
}

function unhighlight(x,y) {
    var old = y.properties.ELEV;
    var u = d3.select(x);
    u.style("stroke", function(d, i) {
            return interp(cScale(old));
        })
}

希望这能让你前进