如何更改 D3 的 diagonal() 使用的贝塞尔曲线函数?
How can I alter the bezier function used by D3's diagonal()?
我正在基于 Bernhard Zuba's D3.js Organizational Chart 在 D3 中创建组织结构图。组织结构图模拟了一个组织,其中任何给定的人(用白色方块表示)下面可能有一百多个人(一个非常扁平的树结构,黑色贝塞尔曲线代表每个父子关系)。
这是树的一部分的屏幕截图:
还有上图中父节点底部的放大图:
问题是子节点和父节点之间的链接往往会聚在一起,导致一条非常粗的黑线和一个非常渐变的斜率,这可能有点碍眼。
我用来生成链接的函数如下:
// Diagonal function
var diagonal = d3.svg.diagonal()
.source(function (d) {
return {
x: d.source.x + (rectW / 2),
y: d.source.y + rectH - 10
};
})
.target(function (d) {
return {
x: d.target.x + (rectW / 2),
y: d.target.y + 10
};
})
.projection(function (d) {
return [d.x, d.y];
});
这里,rectW
是每个节点的宽度,rectH
是每个节点的高度。
我想做的是对用于生成链接的贝塞尔函数做一些细微的调整。具体来说,我想稍微拉平控制点,使曲线起点和终点的曲线更加生动。如果有人能告诉我如何改变 diagonal()
使用的函数来生成贝塞尔曲线,我就能弄清楚剩下的部分。
如果您为此查看 svg.diagonal, I can't really see a direct way to adjust just the control points. You'd think you could use projection 的源代码,但这将转换用于生成路径的所有 4 个点。现在,我想我们可以对投影有点 hacky 并做这样的事情:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.17" data-semver="3.5.17" src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var data = [{
source: {
x: 10,
y: 10
},
target: {
x: 200,
y: 200
}
}, {
source: {
x: 50,
y: 50
},
target: {
x: 200,
y: 200
}
}];
var svg = d3.select('body')
.append('svg')
.attr('width', 205)
.attr('height', 205);
var diagonal = d3.svg.diagonal()
.projection(function(d) {
if (!this.times) this.times = 0;
this.times++;
console.log(this.times);
if (this.times === 1) {
return [d.x, d.y];
} else if (this.times === 2) {
return [d.x - 25, d.y]
} else if (this.times === 3) {
return [d.x + 25, d.y];
} else if (this.times === 4) {
this.times = 0;
return [d.x, d.y];
}
});
svg.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', diagonal)
.style('fill', 'none')
.style('stroke', 'black');
</script>
</body>
</html>
我可能想多了。你最好自己画弧线:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.17" data-semver="3.5.17" src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var data = [{
source: {
x: 10,
y: 10
},
target: {
x: 200,
y: 200
}
}, {
source: {
x: 200,
y: 10
},
target: {
x: 10,
y: 200
}
}];
var svg = d3.select('body')
.append('svg')
.attr('width', 205)
.attr('height', 205);
svg.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', function(d){
var s = d.source,
t = d.target,
m = (s.y + t.y) / 2,
p0 = [s.x, s.y],
p1 = [s.x, m],
p2 = [t.x, m],
p3 = [t.x, t.y];
// adjust constrol points
p1[0] -= 25;
p2[0] += 25;
return "M" + p0 + "C" + p1 + " " + p2 + " " + p3;
})
.style('fill', 'none')
.style('stroke', 'black');
</script>
</body>
</html>
我正在基于 Bernhard Zuba's D3.js Organizational Chart 在 D3 中创建组织结构图。组织结构图模拟了一个组织,其中任何给定的人(用白色方块表示)下面可能有一百多个人(一个非常扁平的树结构,黑色贝塞尔曲线代表每个父子关系)。
这是树的一部分的屏幕截图:
还有上图中父节点底部的放大图:
问题是子节点和父节点之间的链接往往会聚在一起,导致一条非常粗的黑线和一个非常渐变的斜率,这可能有点碍眼。
我用来生成链接的函数如下:
// Diagonal function
var diagonal = d3.svg.diagonal()
.source(function (d) {
return {
x: d.source.x + (rectW / 2),
y: d.source.y + rectH - 10
};
})
.target(function (d) {
return {
x: d.target.x + (rectW / 2),
y: d.target.y + 10
};
})
.projection(function (d) {
return [d.x, d.y];
});
这里,rectW
是每个节点的宽度,rectH
是每个节点的高度。
我想做的是对用于生成链接的贝塞尔函数做一些细微的调整。具体来说,我想稍微拉平控制点,使曲线起点和终点的曲线更加生动。如果有人能告诉我如何改变 diagonal()
使用的函数来生成贝塞尔曲线,我就能弄清楚剩下的部分。
如果您为此查看 svg.diagonal, I can't really see a direct way to adjust just the control points. You'd think you could use projection 的源代码,但这将转换用于生成路径的所有 4 个点。现在,我想我们可以对投影有点 hacky 并做这样的事情:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.17" data-semver="3.5.17" src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var data = [{
source: {
x: 10,
y: 10
},
target: {
x: 200,
y: 200
}
}, {
source: {
x: 50,
y: 50
},
target: {
x: 200,
y: 200
}
}];
var svg = d3.select('body')
.append('svg')
.attr('width', 205)
.attr('height', 205);
var diagonal = d3.svg.diagonal()
.projection(function(d) {
if (!this.times) this.times = 0;
this.times++;
console.log(this.times);
if (this.times === 1) {
return [d.x, d.y];
} else if (this.times === 2) {
return [d.x - 25, d.y]
} else if (this.times === 3) {
return [d.x + 25, d.y];
} else if (this.times === 4) {
this.times = 0;
return [d.x, d.y];
}
});
svg.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', diagonal)
.style('fill', 'none')
.style('stroke', 'black');
</script>
</body>
</html>
我可能想多了。你最好自己画弧线:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.17" data-semver="3.5.17" src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var data = [{
source: {
x: 10,
y: 10
},
target: {
x: 200,
y: 200
}
}, {
source: {
x: 200,
y: 10
},
target: {
x: 10,
y: 200
}
}];
var svg = d3.select('body')
.append('svg')
.attr('width', 205)
.attr('height', 205);
svg.selectAll('path')
.data(data)
.enter()
.append('path')
.attr('d', function(d){
var s = d.source,
t = d.target,
m = (s.y + t.y) / 2,
p0 = [s.x, s.y],
p1 = [s.x, m],
p2 = [t.x, m],
p3 = [t.x, t.y];
// adjust constrol points
p1[0] -= 25;
p2[0] += 25;
return "M" + p0 + "C" + p1 + " " + p2 + " " + p3;
})
.style('fill', 'none')
.style('stroke', 'black');
</script>
</body>
</html>