使用D3.js加载自定义JSON绘制地图时遇TypeError错误求助
问题
尝试将自定义JSON数据加载到D3.js地图中时,持续报错:TypeError: cannot read properties of undefined。使用自定义JSON数据时无法完成映射,似乎无法正确读取yearninteenthirtyeight字段;但使用FreeCodeCamp的示例数据集并读取bachelorsOrHigher字段时,数据能正常加载。多次修改数据集无效,求解决方法。
JS代码
const colors = new Array("#e0f7ff","#b6e2ff","#87c4ff","#5d9eff","#007bff"); // -- GET FILES -- // let gbCounts = "自定义JSON数据地址" let countyGeoFile = "FreeCodeCamp地理数据地址" let gbCountsData let countyGeoData // -- LOAD MAP -- // let map = d3.select('#map') let drawMap = () => { var colorScale = d3 .scaleThreshold() .domain([0, 10, 30, 100, 220]) .range(colors); map.selectAll('path') .data(countyGeoData.features) .enter() .append('path') .attr('d', d3.geoPath()) .attr("stroke", "#333") .attr('class', 'county') .attr("fill", (d, i) => { //d is a county data item //get ID of current data element let currentID = d.id; // console.log(i, currentID) //find education that matches id let county = gbCountsData.find((item) => { if (item.fips === currentID) { // console.log(item.state) return item; } }) return colorScale(county.yearninteenthirtyeight); }) } // -- LOAD MAP DATA -- // d3.json(gbCounts).then( (data, error) => { if(error) { console.log(error); } else { // if no error, load data gbCountsData = data; console.log(gbCountsData) // load map after data is loaded d3.json(countyGeoFile).then( (data, error) => { if(error) { console.log(error); } else { // if no error, load data countyGeoData = topojson.feature(data, data.objects.counties); drawMap() } } ) } } )
HTML代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>OSU Green Book SVG Demo</title> <link rel="stylesheet" href="timeseriesmap.css" /> <script src="https://d3js.org/d3.v7.min.js"></script> <script src="https://d3js.org/topojson.v2.min.js"></script> <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js"></script> --> <style> /* Nothing here so far */ </style> </head> <body> <main class="wrapper"> <div class="container"> <div class="sidebar"> <div class="title"> <h1 class="siderbar-title">The Green Book</h1> <p class="sidebar-text">Body Text</p> </div> <div class="sliderContainer"> <div id="slider"></div> <div class="year start-year">1938</div> <div class="year end-year">1963</div> <div class="zoom-button"></div> </div> <div class="content"></div> </div> <div class="map-container"> <div id="map-tooltip"></div> <div class="map-key"></div> <svg id="map"></svg> </div> </div> </main> <script defer src="timeseriesmap.js" type="text/javascript"></script> </body> </html>
解决方案
报错核心是county变量为undefined,导致无法访问yearninteenthirtyeight字段,修正以下三点即可解决:
- 修正
find回调逻辑:find的回调需要返回布尔值判断匹配,原代码仅在匹配时返回item,不匹配时无返回值,导致find无法正确识别匹配项。 - 统一FIPS编码类型:地理数据中的
d.id是数字类型,自定义JSON中的fips可能是字符串类型,直接用===全等比较会匹配失败。 - 添加兜底逻辑:处理部分县在自定义数据中无对应记录的情况,避免
undefined访问属性报错。
修改后的关键代码片段
.attr("fill", (d, i) => { let currentID = d.id; // 修正find回调,返回布尔值并统一类型比较 let county = gbCountsData.find((item) => { return Number(item.fips) === currentID; }); // 兜底:无对应数据时返回默认灰色 if (!county) { return "#ccc"; } return colorScale(county.yearninteenthirtyeight); })
额外优化建议
- 提前转换
fips类型,避免重复计算:gbCountsData = data.map(item => ({ ...item, fips: Number(item.fips) })); - 改用
Map存储数据,查询效率远高于find:// 加载数据后创建Map const countyMap = new Map(gbCountsData.map(item => [item.fips, item])); // 回调中查询 let county = countyMap.get(currentID.toString());
内容的提问来源于stack exchange,提问作者gb_rsh02
相关产品推荐
相关产品推荐

