You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Flask结合D3-Graphviz时图标加载失败问题

问题根源

你在visualisation.js中使用了Jinja2模板语法{{ url_for() }},但JS文件属于静态资源,不会经过Flask的模板渲染引擎处理,这些模板标签会被浏览器原样解析为无效字符串,导致图片路径错误。而CSS中的background.jpg能正常加载,是因为CSS里的相对路径会被浏览器自动解析为/static/images/background.jpg,符合Flask静态资源的访问规则。

解决方案

以下是三种可行的解决方法,按推荐优先级排序:

方案1:直接使用绝对路径

直接将addImage的路径改为Flask静态资源的绝对路径,无需依赖模板渲染:

function renderString(str){
    newgraphviz.tweenShapes(false)
     .addImage("/static/images/Actor.png", "50px", "50px")
     .addImage("/static/images/File.png", "50px", "50px")
     .addImage("/static/images/System.png", "50px", "50px")
     .addImage("/static/images/Service.png", "50px", "50px")
    .renderDot(str, function() {
      graph.selectAll("title").remove();
      graph.selectAll("text").style("pointer-events", "none");
    });
}

该方法最简单,因为你已经在Flask配置中设置了static_url_path='/static',绝对路径可直接指向正确资源位置。

方案2:在HTML模板中注入静态资源URL

在website.html中,先通过Jinja2渲染出正确的图片URL并定义为全局变量,再让JS读取这些变量:

  1. 修改website.html,在引入visualisation.js前添加全局变量定义:
<script>
window.imagePaths = {
  actor: "{{ url_for('static', filename='images/Actor.png') }}",
  file: "{{ url_for('static', filename='images/File.png') }}",
  system: "{{ url_for('static', filename='images/System.png') }}",
  service: "{{ url_for('static', filename='images/Service.png') }}"
};
</script>
<script src="{{ url_for('static', filename='visualisation.js') }}"></script>
  1. 修改visualisation.js中的renderString函数:
function renderString(str){
    newgraphviz.tweenShapes(false)
     .addImage(window.imagePaths.actor, "50px", "50px")
     .addImage(window.imagePaths.file, "50px", "50px")
     .addImage(window.imagePaths.system, "50px", "50px")
     .addImage(window.imagePaths.service, "50px", "50px")
    .renderDot(str, function() {
      graph.selectAll("title").remove();
      graph.selectAll("text").style("pointer-events", "none");
    });
}

此方法灵活性更高,后续修改静态资源路径时无需改动JS文件。

方案3:将JS代码内嵌到HTML模板中

把visualisation.js的内容直接放到website.html的<script>标签内,这样模板语法会被Flask正确渲染:

<script>
let graph = d3.select("#graph")
let newgraphviz = graph.graphviz()
newgraphviz.transition(function () {
      return d3.transition("main")
          .ease(d3.easeLinear)
          .delay(500)
          .duration(1500);}
  )
  .on("initEnd", render)
  .on("end", draw_edges);

let graph2 = graph.selectAll(".edge").nodes()
console.log(graph2)
function draw_edges() {
  graph.selectAll(".edge")
  .nodes()
  .forEach(function (e, i) {
    setTimeout(() => {
      {
        let ee = d3.select(e);
        ee.select("path")
          .attr("stroke-width", 1)
          .transition()
          .duration(800)
          .attr("stroke", "red")
          .attr("stroke-width", 2);
        ee.select("polygon").transition().duration(800).attr("fill", "red");
      }
    }, 800 * (i + 1));
  });
}

function renderString(str){
    newgraphviz.tweenShapes(false)
     .addImage("{{ url_for('static', filename='images/Actor.png') }}", "50px", "50px")
     .addImage("{{ url_for('static', filename='images/File.png') }}", "50px", "50px")
     .addImage("{{ url_for('static', filename='images/System.png') }}", "50px", "50px")
     .addImage("{{ url_for('static', filename='images/Service.png') }}", "50px", "50px")
    .renderDot(str, function() {
      graph.selectAll("title").remove();
      graph.selectAll("text").style("pointer-events", "none");
    });
}

function render(filename) {
fetch(filename).then(response  => response.text()).then(textAsString => 
     renderString(textAsString));
}
</script>

适合JS代码量较小的场景,避免单独JS文件无法解析模板语法的问题。

验证步骤

修改后,打开浏览器开发者工具(F12),切换到「网络」标签,刷新页面查看图片请求状态。如果仍失败,检查:

  • 图片文件名大小写是否与代码一致(Linux服务器区分大小写)
  • 图片文件是否确实存在于static/images目录下

内容的提问来源于stack exchange,提问作者Hoang Cuong Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 05:54:59