mirror of
https://github.com/konvajs/konva.git
synced 2026-01-09 11:34:38 +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;
|
||||
}
|
||||
|
||||
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 {
|
||||
points?:
|
||||
| number[]
|
||||
@@ -259,6 +296,14 @@ export class Line<
|
||||
points[points.length - 2],
|
||||
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 {
|
||||
points = this.points();
|
||||
}
|
||||
|
||||
@@ -456,6 +456,68 @@ describe('Line', function () {
|
||||
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 () {
|
||||
var stage = addStage();
|
||||
var layer = new Konva.Layer();
|
||||
|
||||
Reference in New Issue
Block a user