dagre-d3画树形拓扑图(包含分组)、流程图

1、安装dagre-d3d3

yarn add dagre-d3 d3

本篇使用d3js v6.x版本,从v3到v4开始用法变化较大
2、画图(html演示)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- ①引入 -->
    <script src="d3.min.js"></script>
    <script src="dagre-d3.min.js"></script>
    <style>
        text {
        font-weight: 300;
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serf;
        font-size: 14px;
        }

        .node rect {
        stroke: #999;
        fill: #fff;
        stroke-width: 1.5px;
        cursor: pointer; 
        }

        .edgePath path {
        stroke: #333;
        stroke-width: 1.5px;
        }

        .clusters rect {
        fill: #d3d7e8;stroke: #999;stroke-width: 1.5px;
        cursor: pointer;
        }

        .label {
        cursor: pointer;
        }
    </style>
</head>
<body>
    <svg width=1200 height=800></svg>
    <script>
        const draw = () => {
            // ②创建 graph 对象
            const graph = new dagreD3.graphlib.Graph({compound:true}) // compound:true为分组必须配置!*
                .setGraph({
                rankdir:'TB',  // 流程图从下向上显示,默认'TB',可取值'TB'、'BT'、'LR'、'RL'
                // zoom: 1,
		        // ranker: "network-simplex",//连线算法
		        // nodesep: 70, // 节点之间间距
		        // ranksep: 100, // 层与层之间的间距
                }) 
                .setDefaultEdgeLabel(() => ({}));
            // 定义节点
            graph.setNode(1, {label: "节点1"});  
            graph.setNode(2, {label: "节点2"});
            graph.setNode(3, {label: "节点3"});
            graph.setNode(4, {label: '节点4-组'});
            // 定义连线
            graph.setEdge(1, 2, {/*属性*/});
            // 定义分组
            graph.setParent(2, 4);
            graph.setParent(3, 4);
            // ③选择 svg 并添加一个g元素作为绘图容器
            // new dagreD3.render()创建渲染器
            const svg = d3.select(`svg`);
            // 在绘图容器上运行渲染器
            svg.append("g").call(new dagreD3.render(), graph)
            .attr("transform", `translate(20,20)`);
        }
        draw()
    </script>
</body>
</html>

运行结果:
在这里插入图片描述
此为最简洁的流程图
参考来源:https://observablehq.com/@fchugunov/hello-dagre
此例子有tooltip等鼠标事件效果


基本图像画好后,除节点、连线样式外的其他附加效果均应在渲染render之后进行
还应会使用d3js画svg图
从零学习d3可参考:svg教程D3(一)D3(二)D3(三)D3(四)
只能说相当有用


附加效果:
d3操作
1、缩放和移动

// 在绘图容器上运行渲染器
const container = svg.append("g").call(new dagreD3.render(), graph)
	.attr("transform", `translate(20,20)`);

var zoom = d3
    .zoom() // 缩放支持
    .scaleExtent([0.5, 2]) // 缩放范围
    .on("zoom", function (current) {
        container.attr("transform", current.transform);
    });
svg.call(zoom); // 缩放生效

.scaleExtent可以使用传递数组来限制缩放,[min, max]其中min是最小比例因子,max是最大比例因子;使用.translateExtent指定[[x0, y0], [x1, y1]]限制用户平移的范围。
运行结果:
请添加图片描述

2、过渡动画居中

let { clientWidth, clientHeight } = svg._groups[0][0];
let { width, height } = graph.graph();
let initScale = 1;
svg
    .transition()
    .duration(1000) // 1s完成过渡
    .call(
    zoom.transform,
    d3.zoomIdentity // 居中显示
        .translate((clientWidth - width * initScale) / 2, (clientHeight - height * initScale) / 2)
        .scale(initScale) // 默认缩放比例
    );

.transform 将变换设置为给定的变换。(d3.zoomIdentity)用于创建缩放变换。)
刷新运行结果:
请添加图片描述


节点属性(引用图片,利用label):

g.setNode(1, {
	// shape:"",  // 节点形状rect(长方形,默认)、circle(圆)、ellipse(椭圆)、diamond(菱形)
	label: `
	<div style="width:164px;height:100px;display:flex;background-image:url(/topoicon/wild.svg);background-size: cover">
	  <span id=1 class='nodeA' style="margin:auto">节点1</span>
	</div>
	`,
	labelType: "html",  //必须!*
	style: "cursor: pointer", // 节点样式,可设置节点的颜色填充、节点边框
	labelStyle: "font-weight:bold;cursor: pointer", // 节点标签样式, 可设置节点标签的文本样式(颜色、粗细、大小)
	padding:0 // 默认10
	// rx: 5, // 设置圆角
    // ry: 5,
    // paddingBottom: 0
    });

运行结果:
在这里插入图片描述


连线的属性:

g.setEdge(edge.fromId, middleNode, {
	//curve: d3.curveStepBefore , //d3.curveBasis, // 设置为贝塞尔曲线
	style: "stroke: #a0cfff; fill: none; stroke-width: 2px", // 连线样式
	arrowheadStyle: "fill: #a0cfff;stroke: #a0cfff;", //箭头样式,可以设置箭头颜色
	arrowhead: "vee" //箭头形状,可以设置 normal,vee,undirected 三种样式,默认为 normal
});

上面的参考例子tooltip跟随鼠标位置,修改为相对于节点位置:
(原)跟随鼠标:
请添加图片描述

var tooltipDiv = d3.select("body").append("div")	
                .attr("class", "tooltip")				
                .style("opacity", 0);   
            
            var showTooltip = function(e){
                var currentNode = graph.node(e.target.id);
                tooltipDiv.transition()		
                .duration(200)		
                .style("opacity", .9);		
                tooltipDiv.html("<br/>"  + (currentNode.name ?? ""))	
                .style("left", (e.pageX) + "px")		
                .style("top", (e.pageY - 60) + "px");
            }
            
            var hideTooltip = function(e){
                tooltipDiv.transition()		
                .duration(500)		
                .style("opacity", 0);
            }
            
            svg.selectAll("g.node,g.cluster").on("mouseenter", showTooltip).on("mouseout", hideTooltip);

(修改后)相对节点:
请添加图片描述

// node数据加如类型,供后面用
graph.setNode(2, {id:2,type:'child',label: "节点2",name:'节点2',});



var tooltipDiv = d3.select("body").append("div")	
    .attr("class", "tooltip")				
    .style("opacity", 0); 
//增加的片段1
let nodeWObject = { root: 164, parent: 232, child: 56 };
let nodeHObject = { root: 100, parent: 86, child: 36 };

var showTooltip = function(e){
    var currentNode = graph.node(e.target.id);
    //增加的片段2
    let scale = d3.zoomTransform(svg.node()).k; //缩放比例
    let containerX = d3.zoomTransform(svg.node()).x; //缩放和移动后的容器的水平移动距离
    let containerY = d3.zoomTransform(svg.node()).y; //...垂直...
    let nodeX = currentNode.x;  //节点相对于容器边缘的水平距离
    let nodeY = currentNode.y;  //...垂直...
    let nodeW = nodeWObject[currentNode.type]; //节点宽,不同类型区分
    let nodeH = nodeWObject[currentNode.type];  //节点高
    let popoverHeigh = 44;  //tooltip高度

    tooltipDiv.transition()		
    .duration(200)		
    .style("opacity", .9);		
    tooltipDiv.html("<br/>"  + (currentNode.name ?? ""))	
    .style("left", 20 + containerX + (nodeX + nodeW / 2) * scale + 'px') //20是body的margin		
    .style("top", 20 + containerY + nodeY * scale - popoverHeigh / 2 + 'px');
}

var hideTooltip = function(e){
    tooltipDiv.transition()		
    .duration(500)		
    .style("opacity", 0);
}

svg.selectAll("g.node,g.cluster").on("mouseenter", showTooltip).on("mouseout", hideTooltip);

参考资料:https://observablehq.com/@fchugunov/hello-dagre
https://blog.csdn.net/qq_57956183/article/details/134708333

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要自定义 Dagre-D3 流程图节点,您需要了解以下几个方面: 1. 节点数据结构:在 Dagre-D3 中,节点通常是一个 JavaScript 对象,包含一些必要的属性,如节点的 ID、宽度、高度、位置等。您可以根据您的需求来定义自己的节点数据结构。 2. 节点渲染:Dagre-D3 通过 SVG 来渲染节点。您可以使用 SVG 的各种元素(如 rect、circle、path 等)来定义您的节点外观和样式。您可以使用 Dagre-D3 提供的一些默认样式,也可以根据自己的需求来定义自己的样式。 3. 节点交互:如果您需要为节点添加交互功能,例如鼠标悬停、点击等,您可以使用 D3.js 提供的事件处理函数来实现。您可以在节点元素上绑定事件处理函数,并在函数中实现您的逻辑。 下面是一个简单的自定义节点的示例代码: ```javascript // 定义节点数据结构 var node = { id: 'node1', width: 80, height: 40, x: 100, y: 100 }; // 渲染节点 var svg = d3.select('svg'); var g = svg.append('g'); var rect = g.append('rect') .attr('width', node.width) .attr('height', node.height) .attr('x', node.x) .attr('y', node.y) .attr('fill', '#ccc'); // 添加节点交互 rect.on('mouseover', function() { d3.select(this).attr('fill', '#f00'); }).on('mouseout', function() { d3.select(this).attr('fill', '#ccc'); }); ``` 在这个示例中,我们首先定义了一个简单的节点数据结构,然后使用 SVG 的 rect 元素来渲染节点。最后,我们为 rect 元素添加了鼠标悬停和鼠标移出事件,以改变节点的填充颜色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值