mirror of
https://github.com/konvajs/konva.git
synced 2026-02-24 20:26:01 +08:00
Merge pull request #2001 from ircubic/fix-bezier-curve-bounds
Fix bounding box calculation for bezier lines.
This commit is contained in:
@@ -56,6 +56,43 @@ function expandPoints(p, tension) {
|
|||||||
return allPoints;
|
return allPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBezierExtremaPoints(points) {
|
||||||
|
const axisPoints = [
|
||||||
|
[points[0], points[2], points[4], points[6]],
|
||||||
|
[points[1], points[3], points[5], points[7]],
|
||||||
|
];
|
||||||
|
const extremaTs: number[] = [];
|
||||||
|
|
||||||
|
for (const axis of axisPoints) {
|
||||||
|
const a = -3 * axis[0] + 9 * axis[1] - 9 * axis[2] + 3 * axis[3];
|
||||||
|
if (a !== 0) {
|
||||||
|
const b = 6 * axis[0] - 12 * axis[1] + 6 * axis[2];
|
||||||
|
const c = -3 * axis[0] + 3 * axis[1];
|
||||||
|
|
||||||
|
const discriminant = b * b - 4 * a * c;
|
||||||
|
if (discriminant >= 0) {
|
||||||
|
const d = Math.sqrt(discriminant);
|
||||||
|
extremaTs.push((-b + d) / (2 * a));
|
||||||
|
extremaTs.push((-b - d) / (2 * a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return extremaTs
|
||||||
|
.filter((t) => t > 0 && t < 1)
|
||||||
|
.flatMap((t) =>
|
||||||
|
axisPoints.map((axis) => {
|
||||||
|
const mt = 1 - t;
|
||||||
|
return (
|
||||||
|
mt * mt * mt * axis[0] +
|
||||||
|
3 * mt * mt * t * axis[1] +
|
||||||
|
3 * mt * t * t * axis[2] +
|
||||||
|
t * t * t * axis[3]
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export interface LineConfig extends ShapeConfig {
|
export interface LineConfig extends ShapeConfig {
|
||||||
points?:
|
points?:
|
||||||
| number[]
|
| number[]
|
||||||
@@ -259,6 +296,14 @@ export class Line<
|
|||||||
points[points.length - 2],
|
points[points.length - 2],
|
||||||
points[points.length - 1],
|
points[points.length - 1],
|
||||||
];
|
];
|
||||||
|
} else if (this.bezier()) {
|
||||||
|
points = [
|
||||||
|
points[0],
|
||||||
|
points[1],
|
||||||
|
...getBezierExtremaPoints(this.points()),
|
||||||
|
points[points.length - 2],
|
||||||
|
points[points.length - 1],
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
points = this.points();
|
points = this.points();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,6 +456,68 @@ describe('Line', function () {
|
|||||||
assert.equal(client.height, 2, 'check height');
|
assert.equal(client.height, 2, 'check height');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getClientRect with bezier', function () {
|
||||||
|
var stage = addStage();
|
||||||
|
var layer = new Konva.Layer();
|
||||||
|
stage.add(layer);
|
||||||
|
|
||||||
|
var line = new Konva.Line({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
points: [25, 5, -47.7791, 20, 107.7837, 35, 25, 50],
|
||||||
|
bezier: true,
|
||||||
|
stroke: '#0f0',
|
||||||
|
});
|
||||||
|
layer.add(line);
|
||||||
|
layer.draw();
|
||||||
|
|
||||||
|
var client = line.getClientRect();
|
||||||
|
|
||||||
|
assert.equal(Math.round(client.x), 4, 'check x');
|
||||||
|
assert.equal(Math.round(client.y), 4, 'check y');
|
||||||
|
assert.equal(Math.round(client.width), 47, 'check width');
|
||||||
|
assert.equal(Math.round(client.height), 47, 'check height');
|
||||||
|
|
||||||
|
line.points([5, 25, 20, -47.7791, 35, 107.7837, 50, 25]);
|
||||||
|
client = line.getClientRect();
|
||||||
|
|
||||||
|
assert.equal(Math.round(client.x), 4, 'check x');
|
||||||
|
assert.equal(Math.round(client.y), 4, 'check y');
|
||||||
|
assert.equal(Math.round(client.width), 47, 'check width');
|
||||||
|
assert.equal(Math.round(client.height), 47, 'check height');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getClientRect with linear bezier', function () {
|
||||||
|
var stage = addStage();
|
||||||
|
var layer = new Konva.Layer();
|
||||||
|
stage.add(layer);
|
||||||
|
|
||||||
|
var line = new Konva.Line({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
points: [5, 5, 20, 5, 35, 5, 50, 5],
|
||||||
|
bezier: true,
|
||||||
|
stroke: '#0f0',
|
||||||
|
});
|
||||||
|
layer.add(line);
|
||||||
|
layer.draw();
|
||||||
|
|
||||||
|
var client = line.getClientRect();
|
||||||
|
|
||||||
|
assert.equal(Math.round(client.x), 4, 'check x');
|
||||||
|
assert.equal(Math.round(client.y), 4, 'check y');
|
||||||
|
assert.equal(Math.round(client.width), 47, 'check width');
|
||||||
|
assert.equal(Math.round(client.height), 2, 'check height');
|
||||||
|
|
||||||
|
line.points([5, 5, 5, 20, 5, 35, 5, 50]);
|
||||||
|
client = line.getClientRect();
|
||||||
|
|
||||||
|
assert.equal(Math.round(client.x), 4, 'check x');
|
||||||
|
assert.equal(Math.round(client.y), 4, 'check y');
|
||||||
|
assert.equal(Math.round(client.width), 2, 'check width');
|
||||||
|
assert.equal(Math.round(client.height), 47, 'check height');
|
||||||
|
});
|
||||||
|
|
||||||
it('line caching', function () {
|
it('line caching', function () {
|
||||||
var stage = addStage();
|
var stage = addStage();
|
||||||
var layer = new Konva.Layer();
|
var layer = new Konva.Layer();
|
||||||
|
|||||||
Reference in New Issue
Block a user