node.js - 如何使用 d3.js 从 Mapbox 检索矢量切片并转换为 geojson?
问题描述
我正在尝试复制 Mike Bostock 的示例:https ://observablehq.com/@d3/mapbox-vector-tiles
由于 Observable 的语言不是原生 Javascript,我无法让示例运行。
特别是,我无法使用以下两个功能:
VectorTile = (await require("https://bundle.run/@mapbox/vector-tile@1")).VectorTile
Protobuf = require("pbf@3/dist/pbf.js")
require()
不是 Javascript 命令。那么,我怎样才能得到这两个库呢?
我尝试了什么:
<script></script>
通过标签插入库加载
await
:let VectorTile = await fetch('https://bundle.run/@mapbox/vector-tile@1.3.1'); let Protobuf = await fetch('https://unpkg.com/pbf@3.0.5/dist/pbf.js');
我不确定是否
require()
来自 node.js。所以我玩弄了node.js,但也没有找到可行的解决方案。
所以,我的问题是:我怎样才能让 Mike Bostock 的例子起作用?或者以更一般的方式:我应该如何从 Mapbox 加载矢量图块,我可以将它们转换为 geojson 格式,就像 Mike 在这个例子中所做的那样?
解决方案
关于您的第一个问题,为了让 Mike Bostock 的示例发挥作用,您可以牢记注意事项:
- Promise 是 Observable 自动处理的东西,而浏览器中的 node.js 或 JavaScript 不会,所以你应该注意它们
- 添加所有必要的库,同时记住您调用它们的方式可能与 Mike 这样做的方式不同。例如,默认情况下,如果您使用 pbf 库,您应该使用 Pbf,而不是 Protobuf(是
require()
的来自 node.js) - 对于 @mapbox/vector-tile 库,请注意它导出 3 个对象,而您需要 VectorTile 函数(在 node.js 中您可以只使用
require().VectorTile
)。你可以在下面看到我是如何为 html 中的 JavaScript 完成的 - 最后,您需要将生成的 svg 代码插入 html 以显示它,这也是 Observable 自动执行的操作
我真的不知道你“应该”如何加载矢量图块,因为我在这个特定的咏叹调方面没有太多专业知识。但是,下面我将 Mike Bostock 的示例转换为 javascript,因此您可以看到它在 Observable 之外是如何工作的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
Map:
<div id='map'></div>
</div>
<script src="https://d3js.org/d3-array.v2.min.js"></script>
<script src="https://d3js.org/d3-geo.v2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-tile@1"></script>
<script src="https://d3js.org/d3-dsv.v2.min.js"></script>
<script src="https://d3js.org/d3-fetch.v2.min.js"></script>
<script src="https://unpkg.com/pbf@3.0.5/dist/pbf.js"></script>
<script src="https://bundle.run/@mapbox/vector-tile@1.3.1"></script>
<script>let VectorTile = _mapbox_vectorTile.VectorTile</script>
<script>
height = 600;
width = 954;
API_KEY = 'cfNfEQR1Qkaz-6mvWl8cpw';// Sign up for an API key: https://www.nextzen.org
projection = d3.geoMercator()
.center([-122.4183, 37.7750])
.scale(Math.pow(2, 21) / (2 * Math.PI))
.translate([width / 2, height / 2]).precision(0);
path = d3.geoPath(projection)
tile = d3.tile()
.size([width, height])
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0]));
function filter({features}, test) {
return {type: "FeatureCollection", features: features.filter(test)};
};
function geojson([x, y, z], layer, filter = () => true) {
if (!layer) return;
const features = [];
for (let i = 0; i < layer.length; ++i) {
const f = layer.feature(i).toGeoJSON(x, y, z);
if (filter.call(null, f, i, features)) features.push(f);
}
return {type: "FeatureCollection", features};
}
tiles_pr = Promise.all(tile().map(async d => {
d.layers = new VectorTile(new Pbf(await d3.buffer(`https://tile.nextzen.org/tilezen/vector/v1/256/all/${d[2]}/${d[0]}/${d[1]}.mvt?api_key=${API_KEY}`))).layers;
return d;
}))
tiles_pr.then(
function(tiles){
//console.log(tiles)
map = `<svg viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">${tiles.map(d => `
<path fill="#eee" d="${path(geojson(d, d.layers.water, d => !d.properties.boundary))}"></path>
<path fill="none" stroke="#aaa" d="${path(geojson(d, d.layers.water, d => d.properties.boundary))}"></path>
<path fill="none" stroke="#000" stroke-width="0.75" d="${path(geojson(d, d.layers.roads))}"></path>
`)}
</svg>`
document.getElementById('map').innerHTML=map;
}
);
</script>
</body>
</html>
推荐阅读
- python - 将 CNN 模型变成课堂
- node.js - express-fileupload 使用文件大小限制时上传原始文件
- go - 使用反射从深度嵌套的结构中提取标签
- python - 终端 Anaconda 未同步到 Jupyter
- php - Forelse 在 laravel 中无法正常工作?
- c# - 如何使用 Visual Studio 单元测试框架或 NUnit 框架在 C# 中模拟对象?
- d3.js - 在矩形上添加一个圆
- google-cloud-firestore - Firestore 数据库设计:团队 vs 游戏 vs 玩家
- javascript - 有没有办法编写一个命令来在 Google 表格中查找和显示一行的内容?
- python-3.x - Jupiter 脚本文件路径