Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix free draw positioning #5718

Merged
merged 8 commits into from
Jun 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/brushes/base_brush.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
ctx.shadowOffsetY = this.shadow.offsetY * zoom;
},

needsFullRender: function() {
var color = new fabric.Color(this.color);
return color.getAlpha() < 1 || !!this.shadow;
},

/**
* Removes brush shadow styles
* @private
Expand Down
25 changes: 15 additions & 10 deletions src/brushes/circle_brush.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
var point = this.addPoint(pointer),
ctx = this.canvas.contextTop;
this._saveAndTransform(ctx);
this.dot(ctx, point);
ctx.restore();
},

dot: function(ctx, point) {
ctx.fillStyle = point.fill;
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();

ctx.restore();
},

/**
Expand All @@ -54,15 +57,10 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
*/
_render: function() {
var ctx = this.canvas.contextTop, i, len,
points = this.points, point;
points = this.points;
this._saveAndTransform(ctx);
for (i = 0, len = points.length; i < len; i++) {
point = points[i];
ctx.fillStyle = point.fill;
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
this.dot(ctx, points[i]);
}
ctx.restore();
},
Expand All @@ -72,7 +70,14 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
* @param {Object} pointer
*/
onMouseMove: function(pointer) {
this.drawDot(pointer);
if (this.needsFullRender()) {
this.canvas.clearContext(this.canvas.contextTop);
this.addPoint(pointer);
this._render();
}
else {
this.drawDot(pointer);
}
},

/**
Expand Down
42 changes: 32 additions & 10 deletions src/brushes/pencil_brush.class.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
(function() {

/**
* PencilBrush class
* @class fabric.PencilBrush
* @extends fabric.BaseBrush
*/
fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ {

/**
* Discard points that are less than `decimate` pixel distant from each other
* @type Number
* @default 0.4
*/
decimate: 0.4,

/**
* Constructor
* @param {fabric.Canvas} canvas
Expand Down Expand Up @@ -45,7 +51,7 @@
*/
onMouseMove: function(pointer) {
if (this._captureDrawingPath(pointer) && this._points.length > 1) {
if (this.needsFullRender) {
if (this.needsFullRender()) {
// redraw curve
// clear top canvas
this.canvas.clearContext(this.canvas.contextTop);
Expand Down Expand Up @@ -106,8 +112,6 @@
_reset: function() {
this._points.length = 0;
this._setBrushStyles();
var color = new fabric.Color(this.color);
this.needsFullRender = (color.getAlpha() < 1);
this._setShadow();
},

Expand Down Expand Up @@ -168,7 +172,7 @@
var path = [], i, width = this.width / 1000,
p1 = new fabric.Point(points[0].x, points[0].y),
p2 = new fabric.Point(points[1].x, points[1].y),
len = points.length, multSignX = 1, multSignY = 1, manyPoints = len > 2;
len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;

if (manyPoints) {
multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;
Expand Down Expand Up @@ -211,10 +215,6 @@
strokeLineJoin: this.strokeLineJoin,
strokeDashArray: this.strokeDashArray,
});
var position = new fabric.Point(path.left + path.width / 2, path.top + path.height / 2);
position = path.translateToGivenOrigin(position, 'center', 'center', path.originX, path.originY);
path.top = position.y;
path.left = position.x;
if (this.shadow) {
this.shadow.affectStroke = true;
path.setShadow(this.shadow);
Expand All @@ -223,6 +223,26 @@
return path;
},

/**
* Decimate poins array with the decimate value
*/
decimatePoints: function(points, distance) {
if (points.length <= 2) {
return points;
}
var zoom = this.canvas.getZoom(), adjustedDistance = Math.pow(distance / zoom, 2),
i, l = points.length - 1, lastPoint = points[0], newPoints = [lastPoint],
cDistance;
for (i = 1; i < l; i++) {
cDistance = Math.pow(lastPoint.x - points[i].x, 2) + Math.pow(lastPoint.y - points[i].y, 2);
if (cDistance >= adjustedDistance) {
lastPoint = points[i];
newPoints.push(lastPoint);
}
}
return newPoints;
},

/**
* On mouseup after drawing the path on contextTop canvas
* we use the points captured to create an new fabric path object
Expand All @@ -231,7 +251,9 @@
_finalizeAndAddPath: function() {
var ctx = this.canvas.contextTop;
ctx.closePath();

if (this.decimate) {
this._points = this.decimatePoints(this._points, this.decimate);
}
var pathData = this.convertPointsToSVGPath(this._points).join('');
if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {
// do not create 0 width/height paths, as they are
Expand Down
15 changes: 8 additions & 7 deletions test/lib/visualTestLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
}
};

function createCanvasForTest(width, height) {
function createCanvasForTest(opts) {
var fabricClass = opts.fabricClass || 'StaticCanvas';
var options = { enableRetinaScaling: false, renderOnAddRemove: false, width: 200, height: 200 };
if (width) {
options.width = width;
if (opts.width) {
options.width = opts.width;
}
if (height) {
options.height = height;
if (opts.height) {
options.height = opts.height;
}
return new fabric.StaticCanvas(null, options);
return new fabric[fabricClass](null, options);
};

function getAbsolutePath(path) {
Expand Down Expand Up @@ -127,7 +128,7 @@
}
QUnit.test(testName, function(assert) {
var done = assert.async();
var fabricCanvas = createCanvasForTest(testObj.width, testObj.height);
var fabricCanvas = createCanvasForTest(testObj);
code(fabricCanvas, function(renderedCanvas) {
var width = renderedCanvas.width;
var height = renderedCanvas.height;
Expand Down
4 changes: 2 additions & 2 deletions test/unit/brushes.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
var pointer = canvas.getPointer({ clientX: 10, clientY: 10});
brush.onMouseDown(pointer);
var pathData = brush.convertPointsToSVGPath(brush._points).join('');
assert.equal(pathData, 'M 9.999 9.999 L 10.001 10.001', 'path data create a small line that looks like a point');
assert.equal(pathData, 'M 9.999 10 L 10.001 10', 'path data create a small line that looks like a point');
});
QUnit.test('fabric pencil brush multiple points', function(assert) {
var brush = new fabric.PencilBrush(canvas);
Expand All @@ -37,7 +37,7 @@
brush.onMouseMove(pointer);
brush.onMouseMove(pointer);
var pathData = brush.convertPointsToSVGPath(brush._points).join('');
assert.equal(pathData, 'M 9.999 9.999 L 10.001 10.001', 'path data create a small line that looks like a point');
assert.equal(pathData, 'M 9.999 10 L 10.001 10', 'path data create a small line that looks like a point');
assert.equal(brush._points.length, 2, 'concident points are discarded');
});
QUnit.test('fabric pencil brush multiple points not discarded', function(assert) {
Expand Down
152 changes: 152 additions & 0 deletions test/visual/freedraw.js

Large diffs are not rendered by default.

Binary file added test/visual/golden/freedrawing1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/visual/golden/freedrawing2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/visual/golden/freedrawing3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/visual/golden/freedrawing4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.