使用geo-albers-usa-territories投影创建D3地图显示异常求助
问题描述
我正在尝试使用d3.js结合geo-albers-usa-territories投影绘制地图,参考官方示例编写代码后,地图显示明显异常,效果如下:
我暂时无法定位问题原因,希望获得相关帮助,完整代码如下:
原始代码
JS逻辑
let margin = { top: 0, right: 50, bottom: 10, left: 50 }, width = 900 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; let projection = geoAlbersUsaTerritories.geoAlbersUsaTerritories() .scale(1200) .translate([520, 305]); const path = d3.geoPath() .projection(projection); const svg = d3.select("#content") .append("svg") .attr('id', 'map') .style("width", width + margin.left + margin.right) .style("height", height + margin.top + margin.bottom) const map = svg.append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .attr('class', 'map') d3.json("https://d3js.org/us-10m.v1.json").then(function (us) { map.selectAll('path') .data(topojson.feature(us, us.objects.nation)) .enter().append("path") .attr("d", path) .attr("class", "outline") .attr("stroke", "red") map.append("path") .datum(topojson.mesh(us, us.objects.states, function (a, b) { return a !== b; })) .attr("class", "mesh") .attr("d", path) .attr('fill', 'none') .attr('stroke', 'blue') });
页面结构
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Map with territories</title> <script src="https://d3js.org/d3.v6.min.js"></script> <script src="https://unpkg.com/topojson-client@3"></script> <script src="https://unpkg.com/geo-albers-usa-territories@0.1.0/dist/geo-albers-usa-territories.js"></script> </head> <body> <div id="content"></div> </body> </html>
解决方案
显示异常由三个问题导致:
- 投影偏移参数不匹配:你设置的
translate([520, 305])和当前画布中心位置不符,导致地图整体偏移出可视区域 - 地理数据源不匹配:你使用的
us-10m.v1.json仅包含美国本土、阿拉斯加、夏威夷的矢量数据,没有geo-albers-usa-territories投影需要的海外领地(波多黎各、美属萨摩亚等)数据 - SVG尺寸设置不规范:用style属性设置SVG宽高容易引发自适应缩放异常,建议直接用attr指定宽高属性
以下是修正后的完整代码:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>含海外领地的美国地图</title> <script src="https://d3js.org/d3.v6.min.js"></script> <script src="https://unpkg.com/topojson-client@3"></script> <script src="https://unpkg.com/geo-albers-usa-territories@0.1.0/dist/geo-albers-usa-territories.js"></script> </head> <body> <div id="content"></div> <script> let margin = { top: 10, right: 10, bottom: 10, left: 10 }, width = 900 - margin.left - margin.right, height = 550 - margin.top - margin.bottom; let projection = geoAlbersUsaTerritories.geoAlbersUsaTerritories() .scale(1100) .translate([width / 2, height / 2]); const path = d3.geoPath() .projection(projection); const svg = d3.select("#content") .append("svg") .attr('id', 'map') .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) const map = svg.append('g') .attr("transform", `translate(${margin.left}, ${margin.top})`) .attr('class', 'map') // 替换为包含海外领地的美国地理数据 d3.json("https://cdn.jsdelivr.net/npm/us-atlas@3.0.0/states-10m.json").then(function (us) { map.append("path") .datum(topojson.feature(us, us.objects.nation)) .attr("d", path) .attr("class", "outline") .attr("fill", "#eee") .attr("stroke", "red") map.append("path") .datum(topojson.mesh(us, us.objects.states, function (a, b) { return a !== b; })) .attr("class", "mesh") .attr("d", path) .attr('fill', 'none') .attr('stroke', 'blue') }); </script> </body> </html>
内容的提问来源于stack exchange,提问作者sprucegoose
相关产品推荐
相关产品推荐

