Django集成d3.js折线图不显示 如何正确添加HTML SVG对象
问题定位
代码存在3个核心问题导致折线图无法展示:
- 前置冗余代码错误:提前编写的SVG初始化逻辑里,错误使用
append("chart")创建了无效的自定义标签(SVG根节点标签必须为svg),且这部分逻辑和LineChart函数内部的SVG创建逻辑完全重复,属于无效代码。 - 图表节点未挂载到DOM:
LineChart函数执行后返回了生成好的SVG节点,但没有将节点插入到页面的#chart容器中,浏览器不会渲染不在DOM树里的节点。 - 测试数据异常:测试用的
aapl数组中存在两条完全相同的Date时间戳,会导致折线绘制出现重叠折返,虽不阻断渲染但不符合时序数据规范。
修复步骤
- 删除所有前置冗余的SVG初始化代码(即从
// set the dimensions and margins of the graph开始到translate偏移的<g>节点创建的全部代码),LineChart函数已经完整封装了SVG创建、边距计算、坐标轴绘制的全流程,无需额外提前初始化。 - 在
LineChart调用完成拿到chart节点后,添加挂载逻辑,将节点插入到#chart容器内。 - 修正测试数据中重复的时间戳,保证x轴时序值唯一。
修复后完整代码
{% load static %} <html> <script src="https://d3js.org/d3.v6.js"></script> <body> <h1> Hello! </h1> <div id="chart"></div> </body> <script> // Copyright 2021 Observable, Inc. // Released under the ISC license. function LineChart(data, { x = ([x]) => x, y = ([, y]) => y, defined, curve = d3.curveLinear, marginTop = 20, marginRight = 30, marginBottom = 30, marginLeft = 40, width = 640, height = 400, xType = d3.scaleUtc, xDomain, xRange = [marginLeft, width - marginRight], yType = d3.scaleLinear, yDomain, yRange = [height - marginBottom, marginTop], yFormat, yLabel, color = "currentColor", strokeLinecap = "round", strokeLinejoin = "round", strokeWidth = 1.5, strokeOpacity = 1, } = {}) { const X = d3.map(data, x); const Y = d3.map(data, y); const I = d3.range(X.length); if (defined === undefined) defined = (d, i) => !isNaN(X[i]) && !isNaN(Y[i]); const D = d3.map(data, defined); if (xDomain === undefined) xDomain = d3.extent(X); if (yDomain === undefined) yDomain = [0, d3.max(Y)]; const xScale = xType(xDomain, xRange); const yScale = yType(yDomain, yRange); const xAxis = d3.axisBottom(xScale).ticks(width / 80).tickSizeOuter(0); const yAxis = d3.axisLeft(yScale).ticks(height / 40, yFormat); const line = d3.line() .defined(i => D[i]) .curve(curve) .x(i => xScale(X[i])) .y(i => yScale(Y[i])); const svg = d3.create("svg") .attr("width", width) .attr("height", height) .attr("viewBox", [0, 0, width, height]) .attr("style", "max-width: 100%; height: auto; height: intrinsic;"); svg.append("g") .attr("transform", `translate(0,${height - marginBottom})`) .call(xAxis); svg.append("g") .attr("transform", `translate(${marginLeft},0)`) .call(yAxis) .call(g => g.select(".domain").remove()) .call(g => g.selectAll(".tick line").clone() .attr("x2", width - marginLeft - marginRight) .attr("stroke-opacity", 0.1)) .call(g => g.append("text") .attr("x", -marginLeft) .attr("y", 10) .attr("fill", "currentColor") .attr("text-anchor", "start") .text(yLabel)); svg.append("path") .attr("fill", "none") .attr("stroke", color) .attr("stroke-width", strokeWidth) .attr("stroke-linecap", strokeLinecap) .attr("stroke-linejoin", strokeLinejoin) .attr("stroke-opacity", strokeOpacity) .attr("d", line(I)); return svg.node(); }; const aapl = [ { "Date": 1641081600000, "Close": 182.01 }, { "Date": 1641168000000, "Close": 179.7 }, { "Date": 1641254400000, "Close": 174.92 }, ]; const chart = LineChart(aapl, { x: d => d.Date, y: d => d.Close, yLabel: "↑ Daily close ($)", width: 400, height: 500, color: "steelblue" }) // 挂载图表到页面容器 document.querySelector("#chart").appendChild(chart) </script> </html>
修复后直接运行即可正常渲染折线图,后续替换真实接口返回的时序数据就能正常使用。
内容的提问来源于stack exchange,提问作者Lopez
相关产品推荐
相关产品推荐

