简体   繁体   English

如何在 React 项目中使用 observablehq D3 图?

[英]How to use observablehq D3 graph in React project?

In react project, I would like to use a tangled tree graph like - tangled-tree-visualization-ii在反应项目中,我想使用一个纠结的树图,比如 - tangled-tree-visualization-ii

How can I use it?我该如何使用它? Since D3 is open source library, is above example code is also open source to use?既然 D3 是开源库,那么上面的示例代码也是开源使用的吗?

I m beginner in D3.我是 D3 的初学者。 So far, 1. Installed the D3 library with npm install d3 --save 2. Created D3 basic bar chart to check d3 is working到目前为止, 1. 使用npm install d3 --save安装了 D3 库 2. 创建了 D3 基本条形图以检查 d3 是否正常工作

Instead of bar chart wanted to use tangled-tree-visualization shared above.而不是条形图想使用上面共享的 tangled-tree-visualization。 But it seems it uses generated minified runtime.js by observablehq.但它似乎使用 observablehq 生成的缩小的 runtime.js。

BarChart.js条形图.js

import React from 'react';
import * as d3 from 'd3';

import { Runtime, Inspector } from "@observablehq/runtime";
import define from "@nitaku/tangled-tree-visualization-ii";

class BarChart extends React.Component {
    componentDidMount() {
        this.drawChart();
    }

    drawChart() {
        const data = this.props.data;
        const svg = d3.select("body").append("svg")
            .attr("width", this.props.width)
            .attr("height", this.props.height);

        const h = this.props.height;

        svg.selectAll("rect")
            .data(data)
            .enter()
            .append("rect")
            .attr("x", (d, i) => i * 70)
            .attr("y", (d, i) => h - 10 * d)
            .attr("width", 65)
            .attr("height", (d, i) => d * 10)
            .attr("fill", "green")

        svg.selectAll("text")
            .data(data)
            .enter()
            .append("text")
            .text((d) => d)
            .attr("x", (d, i) => i * 70)
            .attr("y", (d, i) => h - (10 * d) - 3)

        //selection.attr(“property”, (d, i) => {})
    }

    render() {
        return <div id={"#" + this.props.id}></div>
    }

}

export default BarChart;

App.js应用程序.js

import React from 'react';
import BarChart from './BarChart.js';
import './App.css';

class App extends React.Component {

  state = {
    data: [12, 5, 6, 6, 9, 10],
    width: 700,
    height: 500,
    id: "root"
  }

  render() {
    return (
      <div className="App">
        <BarChart data={this.state.data} width={this.state.width} height={this.state.height} />
      </div>
    );
  }
}

export default App;

Here is an example following their guideline but using react hooks.这是一个遵循他们的指南但使用反应钩子的示例。

When the component is mounted, you have to instance the runtime, specify the cells you want to mount and the html nodes, in this case using ref to point to a div element安装组件时,您必须实例化运行时,指定要安装的单元格和 html 节点,在本例中使用ref指向div元素

  useEffect(() => {
    const runtime = new Runtime();
    runtime.module(notebook, name => {
      if (name === "animation") {
        return new Inspector(animationRef.current);
      }
       if (name === "mutable speed") {
        return {fulfilled: (value) => {
          animationSpeed.current = value;
        }};
      }
    });
  },[]);

animationSpeed is a reference to a mutable speed cell from the observable notebook. animationSpeed是对可观察笔记本中mutable speed单元的引用。 When there is an updated on the react input range you useEffect to update inside the notebook, using animationSpeed reference当反应输入范围有更新时,您使用useEffect在笔记本内更新,使用animationSpeed速度参考

useEffect(() => {
  if(animationSpeed.current){
    animationSpeed.current.value = speed;
    }
  },[speed]);

Here is the functional example.这是功能示例。

ps.附言。 there is a bit o hack to load the modules inside stackoverflow code snippets在stackoverflow代码片段中加载模块有一点技巧

 const { useState, useEffect, useRef, } = React; const App = () => { const [speed, setSpeed] = useState(1); const animationRef = useRef(); const animationSpeed = useRef(); useEffect(() => { const runtime = new Runtime(); runtime.module(notebook, name => { if (name === "animation") { return new Inspector(animationRef.current); } if (name === "mutable speed") { return {fulfilled: (value) => { animationSpeed.current = value; }}; } }); },[]); useEffect(() => { if(animationSpeed.current){ animationSpeed.current.value = speed; } },[speed]); return ( <div className="App"> <small>Speed: {speed}</small> <input type="range" min="0" max="5" step="0.1" value={speed} onChange={(event)=> setSpeed(event.target.valueAsNumber)} /> <div ref={animationRef}></div> </div> ); }; // Render ReactDOM.render( <App / >, document.getElementById("react") );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="react"></div> <script type="module"> import {Runtime, Inspector} from "https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js"; import notebook from "https://api.observablehq.com/@observablehq/how-to-embed-a-notebook-in-a-react-app.js?v=3"; // hack to make module packages global, so the babel transpile code can see it window.Runtime = Runtime; window.Inspector = Inspector; window.notebook = notebook; </script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM