React を使用して d3 フォースディレクテッド グラフを構築する方法 (詳細なチュートリアル)
この記事では主に React で d3 フォースディレクテッド グラフを構築する方法を紹介します。
D3js 強制指示グラフ構築
d3js は、データに基づいてドキュメントを操作できる JavaScript ライブラリです。データはHTML、CSS、SVG、Canvasを使用して表示できます。力指向グラフを使用して、ノード間の多対多の関係を表すことができます。
成果効果: 接続線に矢印があり、ノードをクリックすると、ノードの色と接続線の太さを変更したり、ズームしたりドラッグしたりできます。
バージョン: 4. 2. コードを逆アセンブルします
1. コンポーネント
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import * as d3 from 'd3';
import { Row, Form } from 'antd';
import { chartReq} from './actionCreator';
import './Chart.less';
const WIDTH = 1900;
const HEIGHT = 580;
const R = 30;
let simulation;
class Chart extends Component {
constructor(props, context) {
super(props, context);
this.print = this.print.bind(this);
this.forceChart = this.forceChart.bind(this);
this.state = {
};
}
componentWillMount() {
this.props.dispatch(push('/Chart'));
}
componentDidMount() {
this.print();
}
print() {
let callback = (res) => { // callback获取后台返回的数据,并存入state
let nodeData = res.data.nodes;
let relationData = res.data.rels;
this.setState({
nodeData: res.data.nodes,
relationData: res.data.rels,
});
let nodes = [];
for (let i = 0; i < nodeData.length; i++) {
nodes.push({
id: (nodeData[i] && nodeData[i].id) || '',
name: (nodeData[i] && nodeData[i].name) || '',
type: (nodeData[i] && nodeData[i].type) || '',
definition: (nodeData[i] && nodeData[i].definition) || '',
});
}
let edges = [];
for (let i = 0; i < relationData.length; i++) {
edges.push({
id: (relationData[i] && (relationData[i].id)) || '',
source: (relationData[i] && relationData[i].start.id) || '',
target: (relationData[i] && relationData[i].end.id) || '',
tag: (relationData[i] && relationData[i].name) || '',
});
}
this.forceChart(nodes, edges); // d3力导向图内容
};
this.props.dispatch(chartReq({ param: param }, callback));
}
// func
forceChart(nodes, edges) {
this.refs['theChart'].innerHTML = '';
// 函数内其余代码请看拆解代码
}
render() {
return (
<Row style={{ minWidth: 900 }}>
<p className="outerp">
<p className="theChart" id="theChart" ref="theChart">
</p>
</p>
</Row>
);
}
}
Chart.propTypes = {
dispatch: PropTypes.func.isRequired,
};
function mapStateToProps(state) {
return {
};
}
const WrappedChart = Form.create({})(Chart);
export default connect(mapStateToProps)(WrappedChart);
ログイン後にコピー全体の絵はp.10に描かれます。
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { push } from 'react-router-redux'; import * as d3 from 'd3'; import { Row, Form } from 'antd'; import { chartReq} from './actionCreator'; import './Chart.less'; const WIDTH = 1900; const HEIGHT = 580; const R = 30; let simulation; class Chart extends Component { constructor(props, context) { super(props, context); this.print = this.print.bind(this); this.forceChart = this.forceChart.bind(this); this.state = { }; } componentWillMount() { this.props.dispatch(push('/Chart')); } componentDidMount() { this.print(); } print() { let callback = (res) => { // callback获取后台返回的数据,并存入state let nodeData = res.data.nodes; let relationData = res.data.rels; this.setState({ nodeData: res.data.nodes, relationData: res.data.rels, }); let nodes = []; for (let i = 0; i < nodeData.length; i++) { nodes.push({ id: (nodeData[i] && nodeData[i].id) || '', name: (nodeData[i] && nodeData[i].name) || '', type: (nodeData[i] && nodeData[i].type) || '', definition: (nodeData[i] && nodeData[i].definition) || '', }); } let edges = []; for (let i = 0; i < relationData.length; i++) { edges.push({ id: (relationData[i] && (relationData[i].id)) || '', source: (relationData[i] && relationData[i].start.id) || '', target: (relationData[i] && relationData[i].end.id) || '', tag: (relationData[i] && relationData[i].name) || '', }); } this.forceChart(nodes, edges); // d3力导向图内容 }; this.props.dispatch(chartReq({ param: param }, callback)); } // func forceChart(nodes, edges) { this.refs['theChart'].innerHTML = ''; // 函数内其余代码请看拆解代码 } render() { return ( <Row style={{ minWidth: 900 }}> <p className="outerp"> <p className="theChart" id="theChart" ref="theChart"> </p> </p> </Row> ); } } Chart.propTypes = { dispatch: PropTypes.func.isRequired, }; function mapStateToProps(state) { return { }; } const WrappedChart = Form.create({})(Chart); export default connect(mapStateToProps)(WrappedChart);
2. ノードと接続を構築します
<p className="theChart" id="theChart" ref="theChart"> </p>
3. 力モデルを定義します
let nodes = []; // 节点
for (let i = 0; i < nodeData.length; i++) {
nodes.push({
id: (nodeData[i] && nodeData[i].id) || '',
name: (nodeData[i] && nodeData[i].name) || '', // 节点名称
});
}
let edges = []; // 连线
for (let i = 0; i < relationData.length; i++) {
edges.push({
id: (relationData[i] && (relationData[i].id)) || '',
source: (relationData[i] && relationData[i].start.id) || '', // 开始节点
target: (relationData[i] && relationData[i].end.id) || '', // 结束节点
tag: (relationData[i] && relationData[i].name) || '', // 连线名称
});
}
ログイン後にコピー
simulation.force() を通じて力を設定できます: let nodes = []; // 节点 for (let i = 0; i < nodeData.length; i++) { nodes.push({ id: (nodeData[i] && nodeData[i].id) || '', name: (nodeData[i] && nodeData[i].name) || '', // 节点名称 }); } let edges = []; // 连线 for (let i = 0; i < relationData.length; i++) { edges.push({ id: (relationData[i] && (relationData[i].id)) || '', source: (relationData[i] && relationData[i].start.id) || '', // 开始节点 target: (relationData[i] && relationData[i].end.id) || '', // 结束节点 tag: (relationData[i] && relationData[i].name) || '', // 连线名称 }); }
センタリング: 力の中心、グラフの中心点の位置を設定します。
Collision: ノード衝突力、.strength パラメーター範囲は [0, 1]。
リンク: 接続の力; . distance は、接続の両端のノード間の距離を設定します。Many-Body: .strength パラメータが正の場合は重力をシミュレートし、負の場合は充電力をシミュレートします。. distanceMax パラメータは最大距離を設定します。
- 位置決め: 特定の方向に力が与えられます。 simulation.on を通じて聴力図要素の位置の変化を監視します。
4. svgを描く
- svgを作成し、svg内にgを作成し、g内にノード接続やその他のコンテンツを配置します。
- select: 最初の対応する要素を選択します
const simulation = d3.forceSimulation(nodes) // 指定被引用的nodes数组 .force('link', d3.forceLink(edges).id(d => d.id).distance(150)) .force('collision', d3.forceCollide(1).strength(0.1)) .force('center', d3.forceCenter(WIDTH / 2, HEIGHT / 2)) .force('charge', d3.forceManyBody().strength(-1000).distanceMax(800));
5. 接続を描画します
- シェルを使用して線を接続しますアール曲線描画: (M 開始点 スケール フィル ビューポート
7. ノードを描画する
- ノードとして円を作成します。 .call() はドラッグ関数を呼び出します。
const svg = d3.select('#theChart').append('svg') // 在id为‘theChart'的标签内创建svg .style('width', WIDTH) .style('height', HEIGHT * 0.9) .on('click', () => { console.log('click', d3.event.target.tagName); }) .call(zoom); // 缩放 const g = svg.append('g'); // 则svg中创建g
const edgesLine = svg.select('g') .selectAll('line') .data(edges) // 绑定数据 .enter() // 添加数据到选择集edgepath .append('path') // 生成折线 .attr('d', (d) => { return d && 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y; }) // 遍历所有数据,d表示当前遍历到的数据,返回绘制的贝塞尔曲线 .attr('id', (d, i) => { return i && 'edgepath' + i; }) // 设置id,用于连线文字 .attr('marker-end', 'url(#arrow)') // 根据箭头标记的id号标记箭头 .style('stroke', '#000') // 颜色 .style('stroke-width', 1); // 粗细
8. ノード名
const defs = g.append('defs'); // defs定义可重复使用的元素 const arrowheads = defs.append('marker') // 创建箭头 .attr('id', 'arrow') // .attr('markerUnits', 'strokeWidth') // 设置为strokeWidth箭头会随着线的粗细进行缩放 .attr('markerUnits', 'userSpaceOnUse') // 设置为userSpaceOnUse箭头不受连接元素的影响 .attr('class', 'arrowhead') .attr('markerWidth', 20) // viewport .attr('markerHeight', 20) // viewport .attr('viewBox', '0 0 20 20') // viewBox .attr('refX', 9.3 + R) // 偏离圆心距离 .attr('refY', 5) // 偏离圆心距离 .attr('orient', 'auto'); // 绘制方向,可设定为:auto(自动确认方向)和 角度值 arrowheads.append('path') .attr('d', 'M0,0 L0,10 L10,5 z') // d: 路径描述,贝塞尔曲线 .attr('fill', '#000'); // 填充颜色
9. 接続名
const nodesCircle = svg.select('g') .selectAll('circle') .data(nodes) .enter() .append('circle') // 创建圆 .attr('r', 30) // 半径 .style('fill', '#9FF') // 填充颜色 .style('stroke', '#0CF') // 边框颜色 .style('stroke-width', 2) // 边框粗细 .on('click', (node) => { // 点击事件 console.log('click'); }) .call(drag); // 拖拽单个节点带动整个图
- 10. マウスをノード
const nodesTexts = svg.select('g') .selectAll('text') .data(nodes) .enter() .append('text') .attr('dy', '.3em') // 偏移量 .attr('text-anchor', 'middle') // 节点名称放在圆圈中间位置 .style('fill', 'black') // 颜色 .style('pointer-events', 'none') // 禁止鼠标事件 .text((d) => { // 文字内容 return d && d.name; // 遍历nodes每一项,获取对应的name });
ログイン後にコピーに移動すると、バブルプロンプトが表示されますconst edgesText = svg.select('g').selectAll('.edgelabel') .data(edges) .enter() .append('text') // 为每一条连线创建文字区域 .attr('class', 'edgelabel') .attr('dx', 80) .attr('dy', 0); edgesText.append('textPath')// 设置文字内容 .attr('xlink:href', (d, i) => { return i && '#edgepath' + i; }) // 文字布置在对应id的连线上 .style('pointer-events', 'none') .text((d) => { return d && d.tag; });
ログイン後にコピー12。ドラッグ
nodesCircle.append('title') .text((node) => { // .text设置气泡提示内容 return node.definition; });
simulation.on('tick', () => { // 更新节点坐标 nodesCircle.attr('transform', (d) => { return d && 'translate(' + d.x + ',' + d.y + ')'; }); // 更新节点文字坐标 nodesTexts.attr('transform', (d) => { return 'translate(' + (d.x) + ',' + d.y + ')'; }); // 更新连线位置 edgesLine.attr('d', (d) => { const path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y; return path; }); // 更新连线文字位置 edgesText.attr('transform', (d, i) => { return 'rotate(0)'; }); });
function onDragStart(d) { // console.log('start'); // console.log(d3.event.active); if (!d3.event.active) { simulation.alphaTarget(1) // 设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0,1] .restart(); // 拖拽节点后,重新启动模拟 } d.fx = d.x; // d.x是当前位置,d.fx是静止时位置 d.fy = d.y; } function dragging(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function onDragEnd(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; // 解除dragged中固定的坐标 d.fy = null; } const drag = d3.drag() .on('start', onDragStart) .on('drag', dragging) // 拖拽过程 .on('end', onDragEnd);
function onZoomStart(d) { // console.log('start zoom'); } function zooming(d) { // 缩放和拖拽整个g // console.log('zoom ing', d3.event.transform, d3.zoomTransform(this)); g.attr('transform', d3.event.transform); // 获取g的缩放系数和平移的坐标值。 } function onZoomEnd() { // console.log('zoom end'); } const zoom = d3.zoom() // .translateExtent([[0, 0], [WIDTH, HEIGHT]]) // 设置或获取平移区间, 默认为[[-∞, -∞], [+∞, +∞]] .scaleExtent([1 / 10, 10]) // 设置最大缩放比例 .on('start', onZoomStart) .on('zoom', zooming) .on('end', onZoomEnd);
4. 使用上の注意反応中
nodesCircle.on('click, (node) => { edges_line.style("stroke-width",function(line){ if(line.source.name==node.name || line.target.name==node.name){ return 4; }else{ return 0.5; } }); })
ノードと接続データを追加、削除、または変更した後、print() 関数を再度呼び出してグラフを再構築する必要があります。
データの取得先データはreduxから取得されるのではなく、リクエスト送信後のコールバックによって直接取得されます。 5. 役立つ情報: d3 プロジェクトの検索 URL
D3js のすべてのプロジェクトの検索。 。 関連記事:
vue で前方リフレッシュ効果と後方非リフレッシュ効果を実現する方法
Vue2.5 の Table コンポーネントと Pagination コンポーネントを使用してページング機能を実装する方法 Bootstrap を統合する方法Laravelで4位?jqueryのselectタグのオプション値を取得する方法
jsを使用して選択するオプションを動的に追加する方法(詳細なチュートリアル)
vue.jsを使用してシームレスなスクロール効果を実現する方法
以上がReact を使用して d3 フォースディレクテッド グラフを構築する方法 (詳細なチュートリアル)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









フロントエンドのサーマルペーパーチケット印刷のためのよくある質問とソリューションフロントエンド開発におけるチケット印刷は、一般的な要件です。しかし、多くの開発者が実装しています...

スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

同じIDを持つ配列要素をJavaScriptの1つのオブジェクトにマージする方法は?データを処理するとき、私たちはしばしば同じIDを持つ必要性に遭遇します...

この記事の視差スクロールと要素のアニメーション効果の実現に関する議論では、Shiseidoの公式ウェブサイト(https://www.shisido.co.co.jp/sb/wonderland/)と同様の達成方法について説明します。

Console.log出力の違いの根本原因に関する詳細な議論。この記事では、Console.log関数の出力結果の違いをコードの一部で分析し、その背後にある理由を説明します。 �...

JavaScriptを学ぶことは難しくありませんが、挑戦的です。 1)変数、データ型、関数などの基本概念を理解します。2)非同期プログラミングをマスターし、イベントループを通じて実装します。 3)DOM操作を使用し、非同期リクエストを処理することを約束します。 4)一般的な間違いを避け、デバッグテクニックを使用します。 5)パフォーマンスを最適化し、ベストプラクティスに従ってください。

フロントエンドのVSCodeと同様に、パネルドラッグアンドドロップ調整機能の実装を調べます。フロントエンド開発では、VSCODEと同様のVSCODEを実装する方法...
