如何在WSG84 TopoJSON地图上转换d3.symbol坐标至SVG像素系统?
经纬度转SVG像素坐标并在TopoJSON地图绘制星形标记
我在基于欧盟统计局NUTS数据集的TopoJSON地图上,尝试在指定经纬度[lat, lon]位置绘制星形符号时遇到了困难,不知道如何将这些坐标对转换为SVG像素坐标系。目前我先尝试实现单个位置标记,最终要在地图上绘制多个不同位置,我的代码如下:
问题分析
你的代码存在两个核心问题:
- 坐标顺序错误:D3地理投影要求坐标格式为
[经度(lon), 纬度(lat)],你写的[48, 9]是先纬度后经度,顺序完全颠倒 - 错误使用geoPath生成器:
path()函数用于生成地理路径,仅接受GeoJSON特征对象,不能直接传入坐标数组。正确的坐标转换方式是直接调用你定义的投影函数
修正方案
核心步骤
- 单独提取投影对象,方便后续重复调用
- 将坐标修正为
[lon, lat]的标准格式 - 使用投影函数将地理坐标转换为SVG像素坐标,再通过
translate定位星形标记
修改后的完整代码
JavaScript部分
d3.json("https://raw.githubusercontent.com/eurostat/Nuts2json/master/pub/v1/2016/3035/20M/3.json", function(error, nuts) { if (error) throw error; // 初始化SVG与投影 var width = 700, height = width*(nuts.bbox[3]-nuts.bbox[1])/(nuts.bbox[2]-nuts.bbox[0]), // 单独定义投影对象,便于坐标转换 projection = d3.geoIdentity() .reflectY(true) .fitSize([width,height], topojson.feature(nuts, nuts.objects.gra)), path = d3.geoPath().projection(projection), svg = d3.select("svg").attr("width", width).attr("height", height); // 绘制国家边界 svg.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.cntbn).features) .enter().append("path").attr("d", path) .attr("class",function(bn) { return "cntbn" + (bn.properties.co==="T"?" coastal":""); }); // 绘制NUTS区域边界 svg.append("g").selectAll("path").data(topojson.feature(nuts, nuts.objects.nutsbn).features) .enter().append("path").attr("d", path) .attr("class",function(bn) { return "nutsbn" + (bn.properties.co==="T"?" coastal":"") + ((bn.properties.oth==="T" || bn.properties.lvl==0)?" white":"") + (bn.properties.lvl==3?" thin":""); }); // 单个标记示例:修正坐标顺序为[lon, lat] var singleCoord = [9, 48]; var starSymbol = d3.symbol().type(d3.symbolStar).size(500); // 投影转换得到SVG像素坐标 var pixelPos = projection(singleCoord); svg.append("g") .append("path") .attr("d", starSymbol()) // 调用符号生成器得到路径字符串 .attr("transform", `translate(${pixelPos[0]},${pixelPos[1]})`) .attr("class","location") .attr("fill", "red"); // 多个标记示例:批量处理坐标数组 var multipleCoords = [ [13.405, 52.52], // 柏林 [2.352, 48.857], // 巴黎 [-0.127, 51.507] // 伦敦 ]; svg.append("g") .selectAll("path") .data(multipleCoords) .enter() .append("path") .attr("d", d3.symbol().type(d3.symbolStar).size(300)()) .attr("transform", d => { var px = projection(d); return `translate(${px[0]},${px[1]})`; }) .attr("class","location") .attr("fill", "blue"); });
CSS部分
.graticule { fill: none; stroke-width: 2px; stroke: lightgray; } .cntrg { fill: lightgray; } .cntrg:hover { fill: darkgray; } .nutsrg { fill: #fdbf6f; } .nutsrg:hover { fill: #ff7f00; } .cntbn { fill: none; stroke-width: 1px; stroke: white; } .nutsbn { fill: none; stroke-width: 1px; stroke: #333; } .white { stroke: white; } .thin { stroke-width: 0.5px; } .coastal { stroke: #1f78b4; } .location { stroke: #fff; stroke-width: 1px; }
HTML部分
<!DOCTYPE html> <svg></svg> <link rel="stylesheet" type="text/css" href="style.css"> <script src="https://d3js.org/d3.v5.min.js"></script> <script src="https://d3js.org/d3-request.v1.min.js"></script> <script src="https://d3js.org/topojson.v3.min.js"></script>
关键说明
- 投影函数的核心作用:
projection([lon, lat])是D3地理可视化中坐标转换的标准方式,直接输出SVG画布上的像素坐标[x, y] - 符号生成器调用:
d3.symbol()返回的是生成器函数,必须通过()调用才能得到实际的路径字符串 - 多标记批量处理:利用D3的数据绑定机制,传入坐标数组即可自动遍历生成所有标记,无需重复编写定位逻辑
内容的提问来源于stack exchange,提问作者SdBBdS
相关产品推荐
相关产品推荐

