我正在创建 svg 路径并将其缩放到特定尺寸。让我们假设
100x100
。我正在使用 d3 根据我的要求调整数据。
但是,我想知道,如何使用
pathfit实现与
pathStr
完全相同的输出。这是我在下面尝试的。
function degreeToRadian(d) {
return (d * Math.PI) / 180;
};
function fnData() {
const data = d3.range(0, 11, 1).map((d) => {
const angleRadian = degreeToRadian(d);
return {
index: d,
angleDeg: d,
angleRadian: angleRadian,
x: Math.cos(angleRadian),
y: Math.sin(angleRadian)
}
});
return data;
};
const width = 1280;
const height = 720;
const data = fnData();
//------------------------WITH D3------------------------//
const scaleX = d3
.scaleLinear()
.range([0, 100])
.domain(d3.extent(data, (d) => d.x));
const scaleY = d3
.scaleLinear()
.range([100, 0])
.domain(d3.extent(data, (d) => d.y));
const pathStr = d3
.line()
.x((d) => scaleX(d.x))
.y((d) => scaleY(d.y))(data);
const pathStr2 = d3.line().x(d=>d.x).y(d=>d.y)(data);
//------------------------WITH pathfit------------------------//
const base = {
viewBox: `0 0 ${width} ${height}`,
preserveAspectRatio: "xMidYMid meet" // the default
};
const pathFitter = new Pathfit(base, undefined, pathStr2).scale_with_aspect_ratio(100, 100);
console.log({d3:pathStr, pathfit:pathFitter});
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/pathfit.js"></script>
如果您想使用数据范围作为应扩展到 100*100 维度的框,则必须在
viewBox
中设置这些数据。 d3
可以为您提供四个边的坐标:
const [x1, x2] = d3.extent(data, (d) => d.x);
const [y1, y2] = d3.extent(data, (d) => d.y);
viewBox: `${x1} ${y1} ${x2 - x1} ${y2 - y1}`
如果您想不保留纵横比,而是将数据在两个方向上拉伸到最大尺寸,则必须设置
preserveAspectRatio: "none"
如果你想翻转数据,你必须提供一个预转换值。这确实有点尴尬,就像
d3
一样。由于使用了SVG语法,所以不能直接指定变换中心,而是需要自己找到正确的变换公式matrix
。幸运的是,将数据边界精确地保留在适当位置的颠倒翻转相对容易:
`matrix(1 0 0 -1 0 ${y1 + y2})`
function degreeToRadian(d) {
return (d * Math.PI) / 180;
};
function fnData() {
const data = d3.range(0, 11, 1).map((d) => {
const angleRadian = degreeToRadian(d);
return {
index: d,
angleDeg: d,
angleRadian: angleRadian,
x: Math.cos(angleRadian),
y: Math.sin(angleRadian)
}
});
return data;
};
const width = 1280;
const height = 720;
const data = fnData();
//------------------------WITH D3------------------------//
const scaleX = d3
.scaleLinear()
.range([0, 100])
.domain(d3.extent(data, (d) => d.x));
const scaleY = d3
.scaleLinear()
.range([100, 0])
.domain(d3.extent(data, (d) => d.y));
const pathStr = d3
.line()
.x((d) => scaleX(d.x))
.y((d) => scaleY(d.y))(data);
const pathStr2 = d3.line().x(d=>d.x).y(d=>d.y)(data);
//------------------------WITH pathfit------------------------//
const [x1, x2] = d3.extent(data, (d) => d.x);
const [y1, y2] = d3.extent(data, (d) => d.y);
const base = {
viewBox: `${x1} ${y1} ${x2 - x1} ${y2 - y1}`,
preserveAspectRatio: "none" // do stretch the result
};
const pathFitter = new Pathfit(
base,
undefined,
pathStr2,
`matrix(1 0 0 -1 0 ${y1 + y2})`
).scale_with_aspect_ratio(100, 100);
console.log({d3:pathStr, pathfit:pathFitter});
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/pathfit.js"></script>
这就是尴尬开始的地方(对我来说,作为
pathfit
库的作者)。在其中的某个地方,中间结果被四舍五入,导致最终结果存在较大 (±5) 的差异。设置更高的 precision
似乎并不能解决这个问题。我没有立即解决这个问题的方法。