如何从给定步长的 D3 SVG 贝塞尔曲线中获取点?
How to get points from a D3 SVG bezier curve with given step size?
所以我有一个 D3 SVG 贝塞尔曲线 like this:
我想从 D3 路径中获取具有给定步骤的点的 X、Y 坐标,如下所示:
所以要得到一个等步的坐标对数组。如果可能,不要重新计算贝塞尔曲线。如何在 D3js 中做这样的事情?
借助 here 的二分函数,您可能需要这样的东西:
const
svg = d3.select("svg"),
width = 512,
height = 200;
const data = [];
const curve = "curveBasis";
var walk = function() {
for (let i = 0, v = 2; i < 50; ++i) {
v += Math.random() - 0.5;
v = Math.max(Math.min(v, 4), 0);
data.push({step: i, value: v});
}
}
walk();
walkX = d3.scaleLinear()
.domain([0, 49])
.range([10, width - 10]);
walkY = d3.scaleLinear()
.domain([0, 4])
.range([200 - 10, 10]);
const line = d3.line()
.curve(d3[curve])
.x(d => walkX(d.step))
.y(d => walkY(d.value));
svg
.append("path")
.attr("id", "svgpath")
.attr("d", line(data))
.attr("fill", "none")
.attr("stroke", "black");
var svgpath = document.getElementById("svgpath");
var findYatXbyBisection = function(x, path, error){
var length_end = path.getTotalLength(),
length_start = 0,
point = path.getPointAtLength((length_end + length_start) / 2), // get the middle point
bisection_iterations_max = 50,
bisection_iterations = 0;
error = error || 0.01;
while (x < point.x - error || x > point.x + error) {
// get the middle point
point = path.getPointAtLength((length_end + length_start) / 2);
if (x < point.x) {
length_end = (length_start + length_end)/2;
} else {
length_start = (length_start + length_end)/2;
}
// Increase iteration
if (bisection_iterations_max < ++ bisection_iterations)
break;
}
return point.y
}
for (let i = 0; i < data.length; ++i) {
console.log(findYatXbyBisection(walkX(i), svgpath, 0.01).toFixed(4));
}
<html>
<head>
<meta charset="utf-8" />
<title>SVG Line</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js" integrity="sha512-COTaPOlz12cG4fSfcBsxZsjauBAyldqp+8FQUM/dZHm+ts/jR4AFoJhCqxy8K10Jrf3pojfsbq7fAPTb1XaVkg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<svg id="chart" width="512" height="200">
</svg>
请注意,返回的 Y 值是 SVG 坐标,因此它们从页面顶部的 0 开始。检查 walkY 函数中使用的范围函数以刷新您必须如何反转 D3.js.
中典型折线图和条形图的值
当然,您可以将值推送到您的自定义数组并使用不同的间隔值,例如我使用的总线(路径)宽度的 1/n 而不是 1/50(对于 50 个数据点)。
所以我有一个 D3 SVG 贝塞尔曲线 like this:
我想从 D3 路径中获取具有给定步骤的点的 X、Y 坐标,如下所示:
所以要得到一个等步的坐标对数组。如果可能,不要重新计算贝塞尔曲线。如何在 D3js 中做这样的事情?
借助 here 的二分函数,您可能需要这样的东西:
const
svg = d3.select("svg"),
width = 512,
height = 200;
const data = [];
const curve = "curveBasis";
var walk = function() {
for (let i = 0, v = 2; i < 50; ++i) {
v += Math.random() - 0.5;
v = Math.max(Math.min(v, 4), 0);
data.push({step: i, value: v});
}
}
walk();
walkX = d3.scaleLinear()
.domain([0, 49])
.range([10, width - 10]);
walkY = d3.scaleLinear()
.domain([0, 4])
.range([200 - 10, 10]);
const line = d3.line()
.curve(d3[curve])
.x(d => walkX(d.step))
.y(d => walkY(d.value));
svg
.append("path")
.attr("id", "svgpath")
.attr("d", line(data))
.attr("fill", "none")
.attr("stroke", "black");
var svgpath = document.getElementById("svgpath");
var findYatXbyBisection = function(x, path, error){
var length_end = path.getTotalLength(),
length_start = 0,
point = path.getPointAtLength((length_end + length_start) / 2), // get the middle point
bisection_iterations_max = 50,
bisection_iterations = 0;
error = error || 0.01;
while (x < point.x - error || x > point.x + error) {
// get the middle point
point = path.getPointAtLength((length_end + length_start) / 2);
if (x < point.x) {
length_end = (length_start + length_end)/2;
} else {
length_start = (length_start + length_end)/2;
}
// Increase iteration
if (bisection_iterations_max < ++ bisection_iterations)
break;
}
return point.y
}
for (let i = 0; i < data.length; ++i) {
console.log(findYatXbyBisection(walkX(i), svgpath, 0.01).toFixed(4));
}
<html>
<head>
<meta charset="utf-8" />
<title>SVG Line</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.1/d3.min.js" integrity="sha512-COTaPOlz12cG4fSfcBsxZsjauBAyldqp+8FQUM/dZHm+ts/jR4AFoJhCqxy8K10Jrf3pojfsbq7fAPTb1XaVkg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<svg id="chart" width="512" height="200">
</svg>
请注意,返回的 Y 值是 SVG 坐标,因此它们从页面顶部的 0 开始。检查 walkY 函数中使用的范围函数以刷新您必须如何反转 D3.js.
中典型折线图和条形图的值当然,您可以将值推送到您的自定义数组并使用不同的间隔值,例如我使用的总线(路径)宽度的 1/n 而不是 1/50(对于 50 个数据点)。