【问题标题】:Adding Dots to d3 SVG Map将点添加到 d3 SVG 地图
【发布时间】:2020-02-13 21:17:03
【问题描述】:

我是 d3 新手,在我的 SVG 地图中添加点时遇到了一些麻烦。我正在加载 SVG 地图,然后尝试从我的数据中附加坐标,这是一个对象数组,格式如下:

{schoolName: "Harvard University", gpa: 4, state: "MA", city: "Cambridge", longitude: -71.10973349999999, latitude: 42.3736158}

下面代码的结果是,我在 SVG 标记下方附加了一组圆圈,但地图上没有出现任何圆圈,并且我收到了看起来像我在代码中看不到的语法错误。

翻译错误:

我在这里做错了什么?

var coords = require('./data/coordinates')

document.addEventListener("DOMContentLoaded", () => {

    // loads svg map
    d3.xml('src/data/usa2.svg', function(data){
        document.body.append(data.documentElement)
    })

    // adjusts data to include coordinates for each city
    cities = cities.default
    let schoolData = []
    d3.json("src/data/schoolInfo.json", function(schools){
        schools.map(el => {
            let currentCity = cities.filter(function(cities){return cities.city === el.city})
            el["hs-gpa-avg"] !== null && currentCity.length > 0 ? schoolData.push({"schoolName": el["displayName"], "gpa": el["hs-gpa-avg"], "state": el["state"], "city": el["city"], "longitude": currentCity[0]["longitude"], "latitude": currentCity[0]["latitude"]}) : ''
        })


    var width = 1200,
        height = 720;

    var albersProjection = d3.geoAlbers()
        .scale(1000)
        .rotate([70, 0])
        .center([-15, 35])
        .translate([width/2, height/2]);

    var svg = d3.select('svg')

    svg.selectAll("circle")
        .data(schoolData).enter()
        .append("circle")
        .attr("transform", function(d) {
            let coords = albersProjection([ d.longitude, d.latitude ]);
            return `translate(${coords[0]}px, ${coords[1]}px)`
        })
        .attr("r", "8px")
        .attr("fill", "red")   
    })

})

在解决与翻译相关的错误时,我的圈子仍然放错了位置,正如answer 中所预测的那样:

错位的点:

【问题讨论】:

  • 我已经调整了问题以保留最初的问题 - 否则我的答案的第一部分不再相关,并且问题的意图将发生很大变化。问题应该是捕捉到现在最初存在的两个问题。如果您觉得它不能同时捕获两者,请随时更改我的编辑。

标签: javascript d3.js svg


【解决方案1】:

SVG 转换属性需要数字,没有单位的纯数字。但是,如果您使用 CSS,则可以指定单位(style="transform: ..." 而不是指定转换属性:transform = "...")。

下面的sn-p比较了设置单位和一个CSS样式属性,直接设置transform属性不带单位,设置transform属性直接带单位。它应该在最后一个矩形上导致相同的错误(由于错误而没有正确定位,它应该在蓝色矩形下方):

<svg>
   <rect style="transform:translate(200px,0px)" width="20" height="20" fill="steelblue"></rect>
   <rect transform="translate(100,0)" width="20" height="20" fill="crimson"></rect>   
   <rect transform="translate(200px,50px)" width="20" height="20" fill="orange"></rect>
</svg>

我的错误,在最后一个矩形上:“Error: &lt;rect&gt; attribute transform: Expected ')', "translate(200px,50px)".

这与您相同,解决方案是简单地从您的翻译值中删除 px您还可以使用 .style() 而不是 .attr() 来指定 CSS 属性。


至于你的下一个问题:为什么圆圈仍然没有正确放置,但现在你没有错误,这是一个不同的问题。这是一个常见的问题。

您有一个美国的 SVG 版本 - 这个 SVG 由二维平面上的顶点组成:投影点,其单位为像素。由于 SVG 已经投影,因此您的 SVG 功能已预先投影。

您的地理数据包含以度为单位的 3D 点(球体上的点)。在不知道用于创建 SVG 的投影的情况下,您无法对齐地理点和预投影点。

这是预投影 topojson/geojson 的常见问题(其中坐标位于 2D 空间中,单位为像素)。解决方法都是一样的:

  • 在 SVG 顶部投影地理点时尝试复制用于创建 SVG 的投影(困难)

  • 在绘制地图时,仅对两个图层使用未投影的坐标(没有预制的 SVG,除非您制作了它们)。 (简单)

  • 在绘制地图时,仅对两个图层使用预投影坐标(但要对点进行此操作,您仍然需要知道用于创建 SVG 的投影)。 (不值得)

这些问题和答案解决了类似的问题,只是使用预投影的 topojson/geojson 而不是 SVG(比较公平,因为 geoPath 通常会生成 SVG 矢量):

第二个包含一个指向美国未投影的topojson的链接:

https://bl.ocks.org/mbostock/raw/4090846/us.json

我们可以将其与未投影的点一起使用 - 我们只需对点和区域使用相同的投影。

我们可以将它与 topojson.js 一起使用来生成一个 geojson 数组:

 var geojson = topojson.feature(data,data.objects.states).features;

一旦我们定义了投影,就可以使用projection([long,lat]) 来投影点,并使用d3.geoPath(projection) 来投影geojson。

data 是解析后的 JSON - 传递给 d3.json 回调函数的值。

【讨论】:

  • 谢谢!删除“px”确实摆脱了我的错误。我将深入研究您提供的那些链接。似乎每个都使用geoJSON或TopoJSON,而我只是使用直接的JSON。这会给我带来问题吗?
  • 如果您使用 geoPath,就像您使用某些功能 (.attr("d", d3.geoPath().projection(projection))) 一样,您将为其提供 geojson,因为这是 geoPath 将呈现的唯一内容。虽然这可能是一个误读(并且很可能是,因为看起来您实际上并没有向 geoPath 提供有效的 geojson):如果您向 geoPath 提供无效的 geojson,则不会引发错误并且不会呈现任何内容 - 在这种情况下您尚未分享如何绘制图像中看到的美国各州背景。这将有助于查看它是否不包含在内。
  • 我明白了 - 所以听起来我可能需要将我的 json 文件转换为 geojson 以确保为 geopath 提供有效数据。关于绘制状态背景,它位于我上面代码的第 4 行; d3 加载我的本地 SVG 文件并通过事件侦听器将其附加到 DOM 的主体上。
  • 可以用JSON画圆,没问题。您已经在绘制它们并使用投影定位它们。在我对问题的快速阅读中,我假设代码块中的 geoPath 用于绘制美国各州(出现在屏幕截图中) - 但问题代码中的 geoPath 没有绘制任何内容,因为它没有提供有效的 geojson .在使用 JSON 附加圆圈时,无需转换为 geojson 即可绘制您已经绘制的点。如果美国各州和点不对齐,您应该分享您绘制美国时的代码部分。
  • 在屏幕截图中 - 我假设路径和圆圈之间的 g 应该包含没有任何 d 属性数据的路径:它们应该是空的,因为它们没有提供有效的 geojson (基于问题中的代码)。删除附加这些路径的代码 - 如问题所示 - 应该没有任何后果 (svg.append("g").selectAll("path").data(schoolData)...)
猜你喜欢
  • 2020-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-12
相关资源
最近更新 更多