remove rounding from getClientRect

This commit is contained in:
Anton Lavrenov
2022-03-12 22:28:19 -05:00
parent a75fd53f0e
commit fcf53dc138
13 changed files with 106 additions and 63 deletions

View File

@@ -8,7 +8,7 @@
* Konva JavaScript Framework v8.3.3 * Konva JavaScript Framework v8.3.3
* http://konvajs.org/ * http://konvajs.org/
* Licensed under the MIT * Licensed under the MIT
* Date: Wed Feb 23 2022 * Date: Tue Mar 08 2022
* *
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS) * Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
* Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva) * Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva)
@@ -15001,9 +15001,9 @@
x: pos.x - ap.x, x: pos.x - ap.x,
y: pos.y - ap.y, y: pos.y - ap.y,
}; };
this._fire('transformstart', { evt: e, target: this.getNode() }); this._fire('transformstart', { evt: e.evt, target: this.getNode() });
this._nodes.forEach((target) => { this._nodes.forEach((target) => {
target._fire('transformstart', { evt: e, target }); target._fire('transformstart', { evt: e.evt, target });
}); });
} }
_handleMouseMove(e) { _handleMouseMove(e) {

4
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -322,8 +322,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
var width = Math.ceil(conf.width || rect.width), var width = Math.ceil(conf.width || rect.width),
height = Math.ceil(conf.height || rect.height), height = Math.ceil(conf.height || rect.height),
pixelRatio = conf.pixelRatio, pixelRatio = conf.pixelRatio,
x = conf.x === undefined ? rect.x : conf.x, x = conf.x === undefined ? Math.floor(rect.x) : conf.x,
y = conf.y === undefined ? rect.y : conf.y, y = conf.y === undefined ? Math.floor(rect.y) : conf.y,
offset = conf.offset || 0, offset = conf.offset || 0,
drawBorder = conf.drawBorder || false, drawBorder = conf.drawBorder || false,
hitCanvasPixelRatio = conf.hitCanvasPixelRatio || 1; hitCanvasPixelRatio = conf.hitCanvasPixelRatio || 1;
@@ -335,12 +335,25 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
return; return;
} }
width += offset * 2; // let's just add 1 pixel extra,
height += offset * 2; // because using Math.floor on x, y position may shift drawing
width += offset * 2 + 1;
height += offset * 2 + 1;
x -= offset; x -= offset;
y -= offset; y -= offset;
// if (Math.floor(x) < x) {
// x = Math.floor(x);
// // width += 1;
// }
// if (Math.floor(y) < y) {
// y = Math.floor(y);
// // height += 1;
// }
// console.log({ x, y, width, height }, rect);
var cachedSceneCanvas = new SceneCanvas({ var cachedSceneCanvas = new SceneCanvas({
pixelRatio: pixelRatio, pixelRatio: pixelRatio,
width: width, width: width,

View File

@@ -538,19 +538,19 @@ export class Shape<
// if stroke, for example = 3 // if stroke, for example = 3
// we need to set x to 1.5, but after Math.round it will be 2 // we need to set x to 1.5, but after Math.round it will be 2
// as we have additional offset we need to increase width and height by 1 pixel // as we have additional offset we need to increase width and height by 1 pixel
let roundingOffset = 0; // let roundingOffset = 0;
if (Math.round(strokeWidth / 2) !== strokeWidth / 2) { // if (Math.round(strokeWidth / 2) !== strokeWidth / 2) {
roundingOffset = 1; // roundingOffset = 1;
} // }
const rect = { const rect = {
width: width + roundingOffset, width: width,
height: height + roundingOffset, height: height,
x: x:
-Math.round(strokeWidth / 2 + blurRadius) + -(strokeWidth / 2 + blurRadius) +
Math.min(shadowOffsetX, 0) + Math.min(shadowOffsetX, 0) +
fillRect.x, fillRect.x,
y: y:
-Math.round(strokeWidth / 2 + blurRadius) + -(strokeWidth / 2 + blurRadius) +
Math.min(shadowOffsetY, 0) + Math.min(shadowOffsetY, 0) +
fillRect.y, fillRect.y,
}; };

View File

@@ -62,26 +62,32 @@ export class Arc extends Shape<ArcConfig> {
} }
getSelfRect() { getSelfRect() {
const innerRadius = this.innerRadius() const innerRadius = this.innerRadius();
const outerRadius = this.outerRadius() const outerRadius = this.outerRadius();
const clockwise = this.clockwise() const clockwise = this.clockwise();
const angle = Konva.getAngle(clockwise ? 360 - this.angle() : this.angle()); const angle = Konva.getAngle(clockwise ? 360 - this.angle() : this.angle());
const boundLeftRatio = Math.cos(Math.min(angle, Math.PI)) const boundLeftRatio = Math.cos(Math.min(angle, Math.PI));
const boundRightRatio = 1 const boundRightRatio = 1;
const boundTopRatio = Math.sin(Math.min(Math.max(Math.PI, angle), 3 * Math.PI / 2)) const boundTopRatio = Math.sin(
const boundBottomRatio = Math.sin(Math.min(angle, Math.PI / 2)) Math.min(Math.max(Math.PI, angle), (3 * Math.PI) / 2)
const boundLeft = boundLeftRatio * (boundLeftRatio > 0 ? innerRadius : outerRadius) );
const boundRight = boundRightRatio * (boundRightRatio > 0 ? outerRadius : innerRadius) const boundBottomRatio = Math.sin(Math.min(angle, Math.PI / 2));
const boundTop = boundTopRatio * (boundTopRatio > 0 ? innerRadius : outerRadius) const boundLeft =
const boundBottom = boundBottomRatio * (boundBottomRatio > 0 ? outerRadius : innerRadius) boundLeftRatio * (boundLeftRatio > 0 ? innerRadius : outerRadius);
const boundRight =
boundRightRatio * (boundRightRatio > 0 ? outerRadius : innerRadius);
const boundTop =
boundTopRatio * (boundTopRatio > 0 ? innerRadius : outerRadius);
const boundBottom =
boundBottomRatio * (boundBottomRatio > 0 ? outerRadius : innerRadius);
return { return {
x: Math.round(boundLeft), x: boundLeft,
y: Math.round(clockwise ? -1 * boundBottom : boundTop), y: clockwise ? -1 * boundBottom : boundTop,
width: Math.round(boundRight - boundLeft), width: boundRight - boundLeft,
height: Math.round(boundBottom - boundTop) height: boundBottom - boundTop,
} };
} }
innerRadius: GetSet<number, this>; innerRadius: GetSet<number, this>;

View File

@@ -188,10 +188,10 @@ export class Path extends Shape<PathConfig> {
} }
} }
return { return {
x: Math.round(minX), x: minX,
y: Math.round(minY), y: minY,
width: Math.round(maxX - minX), width: maxX - minX,
height: Math.round(maxY - minY), height: maxY - minY,
}; };
} }
/** /**

View File

@@ -646,10 +646,10 @@ Factory.addGetterSetter(TextPath, 'align', 'left');
* @param {Number} letterSpacing * @param {Number} letterSpacing
* @returns {Number} * @returns {Number}
* @example * @example
* // get line height * // get letter spacing value
* var letterSpacing = shape.letterSpacing(); * var letterSpacing = shape.letterSpacing();
* *
* // set the line height * // set the letter spacing value
* shape.letterSpacing(2); * shape.letterSpacing(2);
*/ */
@@ -662,10 +662,10 @@ Factory.addGetterSetter(TextPath, 'letterSpacing', 0, getNumberValidator());
* @param {String} textBaseline * @param {String} textBaseline
* @returns {String} * @returns {String}
* @example * @example
* // get line height * // get current text baseline
* var textBaseline = shape.textBaseline(); * var textBaseline = shape.textBaseline();
* *
* // set the line height * // set new text baseline
* shape.textBaseline('top'); * shape.textBaseline('top');
*/ */
Factory.addGetterSetter(TextPath, 'textBaseline', 'middle'); Factory.addGetterSetter(TextPath, 'textBaseline', 'middle');

View File

@@ -5,6 +5,7 @@ import {
Konva, Konva,
createCanvas, createCanvas,
compareLayerAndCanvas, compareLayerAndCanvas,
assertAlmostDeepEqual,
} from './test-utils'; } from './test-utils';
describe('Arc', function () { describe('Arc', function () {
@@ -88,7 +89,7 @@ describe('Arc', function () {
layer.add(arc); layer.add(arc);
stage.add(layer); stage.add(layer);
assert.deepEqual(arc.getSelfRect(), { assertAlmostDeepEqual(arc.getSelfRect(), {
x: 0, x: 0,
y: 0, y: 0,
width: 80, width: 80,
@@ -116,7 +117,7 @@ describe('Arc', function () {
layer.add(arc); layer.add(arc);
stage.add(layer); stage.add(layer);
assert.deepEqual(arc.getSelfRect(), { assertAlmostDeepEqual(arc.getSelfRect(), {
x: -80, x: -80,
y: -80, y: -80,
width: 160, width: 160,
@@ -140,7 +141,7 @@ describe('Arc', function () {
layer.add(arc); layer.add(arc);
stage.add(layer); stage.add(layer);
assert.deepEqual(arc.getSelfRect(), { assertAlmostDeepEqual(arc.getSelfRect(), {
x: 0, x: 0,
y: -80, y: -80,
width: 80, width: 80,
@@ -163,14 +164,14 @@ describe('Arc', function () {
layer.add(arc); layer.add(arc);
stage.add(layer); stage.add(layer);
assert.deepEqual(arc.getSelfRect(), { assertAlmostDeepEqual(arc.getSelfRect(), {
x: 25, x: 25,
y: 0, y: 0,
width: 55, width: 55,
height: 69, height: 69.282032302755,
}); });
}); });
it('cache', function () { it('cache', function () {
var stage = addStage(); var stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();

View File

@@ -831,7 +831,8 @@ describe('Caching', function () {
group.cache(); group.cache();
const canvas = group._cache.get('canvas').scene; const canvas = group._cache.get('canvas').scene;
assert.equal(canvas.width, 105 * canvas.pixelRatio); console.log(canvas.width / 2);
assert.equal(canvas.width, 106 * canvas.pixelRatio);
}); });
it('cache group with rectangle with fill and opacity', function () { it('cache group with rectangle with fill and opacity', function () {
@@ -1468,7 +1469,7 @@ describe('Caching', function () {
layer.draw(); layer.draw();
assert.equal( assert.equal(
circle._cache.get('canvas').filter.width, circle._cache.get('canvas').filter.width,
20 * circle._cache.get('canvas').filter.pixelRatio 21 * circle._cache.get('canvas').filter.pixelRatio
); );
circle.filters([]); circle.filters([]);
// TODO: should we clear cache canvas? // TODO: should we clear cache canvas?

View File

@@ -10,6 +10,7 @@ import {
compareLayerAndCanvas, compareLayerAndCanvas,
cloneAndCompareLayer, cloneAndCompareLayer,
isNode, isNode,
assertAlmostDeepEqual,
} from './test-utils'; } from './test-utils';
describe('Path', function () { describe('Path', function () {
@@ -1280,7 +1281,12 @@ describe('Path', function () {
}); });
layer.add(path); layer.add(path);
var rect = path.getClientRect(); var rect = path.getClientRect();
assert.deepEqual(rect, { x: 60, y: 184, width: 106, height: 102 }); assertAlmostDeepEqual(rect, {
x: 59.55,
y: 183.55,
width: 106,
height: 102,
});
}); });
it('getClientRect of complex path', function () { it('getClientRect of complex path', function () {
@@ -1310,7 +1316,12 @@ describe('Path', function () {
layer.add(back); layer.add(back);
layer.draw(); layer.draw();
assert.deepEqual(rect, { x: 9, y: 66, width: 95, height: 55 }); assertAlmostDeepEqual(rect, {
x: 8.6440882161882,
y: 65.75902834,
width: 94.74182356762,
height: 55.4919433,
});
}); });
it('getClientRect of another complex path', function () { it('getClientRect of another complex path', function () {
@@ -1339,11 +1350,11 @@ describe('Path', function () {
layer.add(back); layer.add(back);
layer.draw(); layer.draw();
assert.deepEqual(rect, { assertAlmostDeepEqual(rect, {
x: 49, x: 49,
y: 49.7, y: 49.7086649,
width: 215, width: 215,
height: 71.39999999999999, height: 71.3826701999,
}); });
}); });
@@ -1372,7 +1383,12 @@ describe('Path', function () {
layer.add(back); layer.add(back);
layer.draw(); layer.draw();
assert.deepEqual(rect, { x: 49, y: 49, width: 43, height: 48 }); assertAlmostDeepEqual(rect, {
x: 48.981379,
y: 48.996825,
width: 42.84717526,
height: 48.057550000000006,
});
}); });
it('getClientRect for arc', function () { it('getClientRect for arc', function () {
@@ -1408,15 +1424,15 @@ describe('Path', function () {
layer.add(back); layer.add(back);
layer.draw(); layer.draw();
assert.deepEqual(rect, { assertAlmostDeepEqual(rect, {
x: 0, x: 0,
y: 0, y: 0,
width: 132.53012048192795, width: 132.4001878816343,
height: 100, height: 100,
}); });
}); });
it.skip('getClientRect on scaled', function () { it('getClientRect on scaled', function () {
var stage = addStage(); var stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();
stage.add(layer); stage.add(layer);
@@ -1444,7 +1460,7 @@ describe('Path', function () {
layer.add(back); layer.add(back);
layer.draw(); layer.draw();
assert.deepEqual(rect, { assertAlmostDeepEqual(rect, {
height: 201.99999999999994, height: 201.99999999999994,
width: 201.99999999999994, width: 201.99999999999994,
x: 99, x: 99,

View File

@@ -203,7 +203,7 @@ describe('RegularPolygon', function () {
var box = poly.getClientRect(); var box = poly.getClientRect();
assertAlmostEqual(box.width, 92.60254037844388); assertAlmostEqual(box.width, 91.60254037844388);
assertAlmostEqual(box.height, 81.00000000000003); assertAlmostEqual(box.height, 80.00000000000003);
}); });
}); });

View File

@@ -2509,7 +2509,7 @@ describe('Transformer', function () {
}); });
}); });
it.only('transform events check', function () { it('transform events check', function () {
var stage = addStage(); var stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();
stage.add(layer); stage.add(layer);

View File

@@ -384,3 +384,9 @@ export const assertAlmostEqual = function (val1, val2) {
throw new Error('Expected ' + val1 + ' to be almost equal to ' + val2); throw new Error('Expected ' + val1 + ' to be almost equal to ' + val2);
} }
}; };
export const assertAlmostDeepEqual = function (obj1, obj2) {
for (var key1 in obj1) {
assertAlmostEqual(obj1[key1], obj2[key1]);
}
};