首页 > 解决方案 > 如何将 ObservableHq 简单算法解释为可重用的代码片段?

问题描述

D3js 解决方案的主要来源是observableHq.com,但似乎不可能(?)通过复制/粘贴重用算法......是吗?即使检查这样的教程,也没有简单的方法(使用更少的插件或程序员的时间消耗!)来检查和重用.

示例:我需要一个新的 2020 D3js v5算法用于缩进树可视化,并且有一个很好的解决方案:observableHq.com/@d3/indented-tree
下载没有用,因为是基于复杂的 运行时类...

但是,似乎是一个简单的图表生成算法,

chart = {  // the indented-tree algorithm
  const nodes = root.descendants();
  const svg = d3.create("svg")// ...
  // ...
  return svg.node();
}

我是否可以通过简单的人工逐步将其转换为简单的 HTML,无需复杂的改编,以不使用Runtime 类<script src="https://d3js.org/d3.v5.min.js"></script>开始和结束?


更多细节作为例子

想象一下我对引用的 indented-tree algorithm的逐步说明,我无法精通并需要您的帮助:

假设从一个干净的 HTML5 模板开始。例如:

<!DOCTYPE html>
<head>
    <meta charset="utf-8">
    <title>Indented Tree</title>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script>
    function onLOAD() {
        console.log("Hello onLoad!")
        // all copy-paste and adaptations HERE.
        console.log("!Bye!")
    } // \onLOAD
    </script>
</head>
<body onload="onLOAD()">
  <script>
    console.log("Hello!")
    // global INITIALIZATIONS HERE.
  </script>
</body>
</html>
  1. 准备全局变量,似乎root,,nodeSize=17width

  2. 准备数据... JSON数据很丑./files/e6537420...,我用它的真实名称移动到项目的根目录,flare-2.json.

  3. 读取 JSON 数据的简单而经典的 D3js 方法: d3.json("./flare-2.json").then( data=> console.log(data) );
    必须测试并检查无 CORS 错误等。

  4. 准备数据作为root变量。全部进入data => {} 块以避免同步问题......
    似乎 root基于function(d3,data) { let i = 0; return d3.hierarchy(data).eachBefore(d => d.index = i++); }.

  5. chart =上面引用的复制粘贴,在root用数据初始化之后。

  6. ...


常问问题

评论问题和答案:

@Mehdi -   你能解释一下在代码中包含 D3 脚本标签和使用运行时库的问题吗?

原始的 ObservableHq 算法很简单时,我需要另一种方法,一种简单的方法来重用它,通过复制/粘贴和最小的调整。

@Mehdi -   你读过下载和嵌入笔记本教程吗?

是的,那里没有消息:没有关于如何重用代码的“人工指令”......只有“安装它”和“安装那个”。没有关于我上面解释过的“复制/粘贴和最小调整”的说明。

(@nobody) - 你需要什么作为答案?

正如我在上面展示的,一个简单的人类可读的逐步转换过程......理想情况下,最终结果可以通过测试,证明它可以在例如 JSFiddle 上工作,并带有复制/粘贴代码等等适应线来表明你的观点。

标签: d3.jscode-reuseobservablehq

解决方案


2020年11月编辑

Observable 现在有一个embed特性,详情在这个页面

原帖

这是将链接的可观察图表移植到自托管网页的分步过程,方法是复制粘贴代码,而无需使用可观察runtime

从 HTML 页面和 HTML 页面中引用的 JavaScript 文件开始。假设 Web 服务器正在运行并且配置合适。

  1. 获取数据。
  • 如果您想使用自己的数据而不是笔记本中使用的数据,请在您的 Web 服务器上的目录中提供数据文件。
  • 否则,请使用每个单元格菜单中的Download JSON链接下载连接到笔记本的每个输入数据集。data

可观察的笔记本单元菜单的屏幕截图

  1. 使用加载页面中的每个数据集d3-fetch
d3.json("/path/to/data.json").then(function(data) {
  console.log(data); // [{"Hello": "world"}, …]
});
  1. 获取笔记本中每个包含变量或函数的单元格的内容,然后将其放入.then上一步的函数中。此笔记本可视化工具有助于识别相关单元格。

  2. 适当地调整刚刚复制的函数的语法。例如,以下笔记本单元格:

root = { let i = 0; return d3.hierarchy(data).eachBefore(d => d.index = i++); }

可以转化为:

function getRoot(){
   let i = 0;
    return d3.hierarchy(data).eachBefore(d => d.index = i++);
}

root = getRoot()
  1. 如果笔记本中的某些功能需要,请定义一个变量width,并使用所需的值对其进行初始化。

  2. 调整 DOM 操作代码以便将元素附加到 DOM,而不是依赖于可观察运行时的隐式执行。

下面截图中的演示:

d3.json("https://rawcdn.githack.com/d3/d3-hierarchy/46f9e8bf1a5a55e94c40158c23025f405adf0be5/test/data/flare.json").then(function(data) {

  const width = 800
    , nodeSize = 17
    , format = d3.format(",")
    , getRoot = function(){
       let i = 0;
        return d3.hierarchy(data).eachBefore(d => d.index = i++);
    }
    , columns = [
      {
        label: "Size", 
        value: d => d.value, 
        format, 
        x: 280
      },
      {
        label: "Count", 
        value: d => d.children ? 0 : 1, 
        format: (value, d) => d.children ? format(value) : "-", 
        x: 340
      }
    ]
    , root = getRoot()
    , chart = function() {
      const nodes = root.descendants();

      const svg = d3.select('#chart')
          .attr("viewBox", [-nodeSize / 2, -nodeSize * 3 / 2, width, (nodes.length + 1) * nodeSize])
          .attr("font-family", "sans-serif")
          .attr("font-size", 10)
          .style("overflow", "visible");


  const link = svg.append("g")
      .attr("fill", "none")
      .attr("stroke", "#999")
    .selectAll("path")
    .data(root.links())
    .join("path")
      .attr("d", d => `
        M${d.source.depth * nodeSize},${d.source.index * nodeSize}
        V${d.target.index * nodeSize}
        h${nodeSize}
      `);

      const node = svg.append("g")
        .selectAll("g")
        .data(nodes)
        .join("g")
          .attr("transform", d => `translate(0,${d.index * nodeSize})`);

      node.append("circle")
          .attr("cx", d => d.depth * nodeSize)
          .attr("r", 2.5)
          .attr("fill", d => d.children ? null : "#999");

      node.append("text")
          .attr("dy", "0.32em")
          .attr("x", d => d.depth * nodeSize + 6)
          .text(d => d.data.name);

      node.append("title")
          .text(d => d.ancestors().reverse().map(d => d.data.name).join("/"));

      for (const {label, value, format, x} of columns) {
        svg.append("text")
            .attr("dy", "0.32em")
            .attr("y", -nodeSize)
            .attr("x", x)
            .attr("text-anchor", "end")
            .attr("font-weight", "bold")
            .text(label);

        node.append("text")
            .attr("dy", "0.32em")
            .attr("x", x)
            .attr("text-anchor", "end")
            .attr("fill", d => d.children ? null : "#555")
          .data(root.copy().sum(value).descendants())
            .text(d => format(d.value, d));
      }

  }

  chart()
    
}).catch(function(err) {
  console.log('error processing data', err)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.min.js"></script>
<svg id = 'chart'></svg>


推荐阅读