【问题标题】:Access svg attributes from index.html in d3.js从 d3.js 中的 index.html 访问 svg 属性
【发布时间】:2021-06-01 16:33:46
【问题描述】:

我正在尝试复制这个d3.js worldmap:

https://www.d3-graph-gallery.com/graph/backgroundmap_basic.html

但是我想将代码重新组织成两部分,index.htmlWorldmap.js

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Worldmap</title>
    <script src="https://d3js.org/d3.v6.js"></script>
    <script type="text/javascript" src=Worldmap.js></script>

  </head>

  <body>
    <svg id="my_dataviz" width="400" height="300"></svg>
  </body>
</html>

Worldmap.js:


// The svg
var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height");

// Map and projection
var projection = d3.geoNaturalEarth1()
    .scale(width / 1.3 / Math.PI)
    .translate([width / 2, height / 2])

// Load external data and boot
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson",
   function(data){

    // Draw the map
    svg.append("g")
        .selectAll("path")
        .data(data.features)
        .enter().append("path")
            .attr("fill", "#69b3a2")
            .attr("d", d3.geoPath()
                .projection(projection)
            )
            .style("stroke", "#fff")
})

但是我得到以下错误:

Uncaught TypeError: node is null

selection_attr https://d3js.org/d3.v6.js:1835
<anonymous> Worldmap.js:6

我在这里做错了什么? 我想d3.js 不能从 index.html 中选择svg 属性?

【问题讨论】:

  • &lt;script type="text/javascript" src=Worldmap.js&gt;&lt;/script&gt; 移动到体内。您仍然收到错误消息吗?
  • 感谢您的意见。错误消失了,但没有显示世界地图。
  • 要让脚本文件运行 DOM 被解析(并且&lt;svg&gt; 元素存在),设置defer 属性; &lt;script type="text/javascript" defer src=Worldmap.js&gt;&lt;/script&gt; 你把&lt;script&gt; 标签放在哪里 都没有关系
  • 不,var svg = d3.select("svg") 正在寻找 DOM 中的 &lt;svg&gt; 元素.. 还没有。在过去,人们会建议将&lt;script&gt; 一直放在 HTML 文件的底部。见DOM 101 Lesson
  • 是的,但是HTML文件是从从上到下解析的;因此,如果您在 HTML 文件的顶部执行 &lt;script&gt;(没有 defer),则 &lt;svg&gt; 尚不存在。

标签: javascript svg d3.js


【解决方案1】:
  1. 使用d3.json 作为承诺:
const url = "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson";
d3.json(url)
  .then(drawMap)
  .catch(err => console.log(err));
  1. 使用数据调用投影:
.attr("d", d => d3.geoPath().projection(projection)(d))

const svg = d3.select("svg");
const width = parseInt(svg.attr("width"));
const height = parseInt(svg.attr("height"));

// Map and projection
var projection = d3.geoNaturalEarth1()
    .scale(width / 1.3 / Math.PI)
    .translate([width / 2, height / 2])

// Load external data and boot

const drawMap = data => {
    // Draw the map
    svg.append("g")
        .selectAll("path")
        .data(data.features)
        .enter()
        .append("path")
            .attr("fill", "#69b3a2")
            .attr("d", d => d3.geoPath()
                .projection(projection)(d))
            .style("stroke", "#fff")
};

const url = "https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson";
d3.json(url)
    .then(drawMap)
  .catch(err => console.log(err));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js"></script>

<svg width="500" height="500" />

【讨论】:

  • 感谢您的回答。但是,这仅在我将所有这些都放入同一个文件时才有效。如果我尝试使用两个单独的文件的方法,比如在 OP 中,它不起作用。
  • const svg = d3.select("svg");之后添加console.log(svg)
  • 另外,把document.addEventListener("DOMContentLoaded", () =&gt; console.log('READY'))放在你的JS文件的第一行,看看它是否在前面的控制台日志之前。
  • 添加document.addEventListener("DOMContentLoaded", onReady)
  • ...和const onReady = () =&gt; { ... all the code in worldmap.js ... }
猜你喜欢
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多