Skip to content

Commit

Permalink
Merge pull request fabricjs#607 from Kienz/dashedStroke
Browse files Browse the repository at this point in the history
Implement dashed stroke + some fixes with stroke, fill, removeShadow and clipTo + fixes in brushes. Closes fabricjs#603
  • Loading branch information
kangax committed May 4, 2013
2 parents d5987be + e4287ac commit f297127
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 111 deletions.
10 changes: 10 additions & 0 deletions src/base_brush.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,15 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
ctx.shadowColor = this.shadowColor || this.color;
ctx.shadowOffsetX = this.shadowOffsetX;
ctx.shadowOffsetY = this.shadowOffsetY;
},

/**
* Remove brush shadow styles
*/
removeShadowStyles: function() {
var ctx = this.canvas.contextTop;

ctx.shadowColor = '';
ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
}
});
6 changes: 2 additions & 4 deletions src/circle.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,9 @@
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top : 0, this.radius, 0, piBy2, false);
ctx.closePath();

this._renderFill(ctx);
this._removeShadow(ctx);
if (this.stroke) {
ctx.stroke();
}
this._renderStroke(ctx);
},

/**
Expand Down
2 changes: 2 additions & 0 deletions src/circle_brush.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ fabric.CircleBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabri
this.canvas.add(circle);
}

this.canvas.clearContext(this.canvas.contextTop);
this.removeShadowStyles();
this.canvas.renderOnAddition = originalRenderOnAddition;
this.canvas.renderAll();
},
Expand Down
6 changes: 2 additions & 4 deletions src/ellipse.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,9 @@
}
ctx.transform(1, 0, 0, this.ry/this.rx, 0, 0);
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top : 0, this.rx, 0, piBy2, false);
if (this.stroke) {
ctx.stroke();
}
this._removeShadow(ctx);

this._renderFill(ctx);
this._renderStroke(ctx);
ctx.restore();
},

Expand Down
82 changes: 62 additions & 20 deletions src/image.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,11 @@
this._setShadow(ctx);
this.clipTo && fabric.util.clipContext(this, ctx);
this._render(ctx);
this.clipTo && ctx.restore();
this._removeShadow(ctx);

if (this.stroke) {
this._stroke(ctx);
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
this._renderStroke(ctx);
this.clipTo && ctx.restore();

if (this.active && !noTransform) {
this.drawBorders(ctx);
Expand All @@ -121,18 +120,40 @@
ctx.restore();
},

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_stroke: function(ctx) {
ctx.save();
ctx.lineWidth = this.strokeWidth;
ctx.strokeStyle = this.stroke;
ctx.strokeRect(
-this.width / 2,
-this.height / 2,
this.width,
this.height);
ctx.beginPath();
ctx.strokeRect(-this.width / 2, -this.height / 2, this.width, this.height);
ctx.beginPath();
ctx.restore();
},

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderDashedStroke: function(ctx) {
var x = -this.width/2,
y = -this.height/2,
w = this.width,
h = this.height;

ctx.lineWidth = this.strokeWidth;
ctx.strokeStyle = this.stroke;
ctx.beginPath();
fabric.util.drawDashedLine(ctx, x, y, x+w, y, this.strokeDashArray);
fabric.util.drawDashedLine(ctx, x+w, y, x+w, y+h, this.strokeDashArray);
fabric.util.drawDashedLine(ctx, x+w, y+h, x, y+h, this.strokeDashArray);
fabric.util.drawDashedLine(ctx, x, y+h, x, y, this.strokeDashArray);
ctx.closePath();
},

/**
* Returns object representation of an instance
* @param {Array} propertiesToInclude
Expand All @@ -150,16 +171,37 @@
* @return {String} svg representation of an instance
*/
toSVG: function() {
return '<g transform="' + this.getSvgTransform() + '">'+
'<image xlink:href="' + this.getSvgSrc() + '" '+
'style="' + this.getSvgStyles() + '" ' +
// we're essentially moving origin of transformation from top/left corner to the center of the shape
// by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
// so that object's center aligns with container's left/top
'transform="translate('+ (-this.width/2) + ' ' + (-this.height/2) + ')" ' +
'width="' + this.width + '" ' +
'height="' + this.height + '"' + '></image>' +
'</g>';
var markup = [];

markup.push(
'<g transform="', this.getSvgTransform(), '">',
'<image xlink:href="', this.getSvgSrc(),
'" style="', this.getSvgStyles(),
// we're essentially moving origin of transformation from top/left corner to the center of the shape
// by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
// so that object's center aligns with container's left/top
'" transform="translate(' + (-this.width/2) + ' ' + (-this.height/2) + ')',
'" width="', this.width,
'" height="', this.height,
'"></image>'
);

if (this.stroke || this.strokeDashArray) {
var origFill = this.fill;
this.fill = null;
markup.push(
'<rect ',
'x="', (-1 * this.width / 2), '" y="', (-1 * this.height / 2),
'" width="', this.width, '" height="', this.height,
'" style="', this.getSvgStyles(),
'"/>'
);
this.fill = origFill;
}

markup.push('</g>');

return markup.join('');
},

/**
Expand Down
23 changes: 19 additions & 4 deletions src/line.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@
ctx.translate(this.left, this.top);
}

// move from center (of virtual box) to its left/top corner
ctx.moveTo(this.width === 1 ? 0 : (-this.width / 2), this.height === 1 ? 0 : (-this.height / 2));
ctx.lineTo(this.width === 1 ? 0 : (this.width / 2), this.height === 1 ? 0 : (this.height / 2));
if (!this.strokeDashArray || this.strokeDashArray && fabric.StaticCanvas.supports('setLineDash')) {
// move from center (of virtual box) to its left/top corner
ctx.moveTo(this.width === 1 ? 0 : (-this.width / 2), this.height === 1 ? 0 : (-this.height / 2));
ctx.lineTo(this.width === 1 ? 0 : (this.width / 2), this.height === 1 ? 0 : (this.height / 2));
}

ctx.lineWidth = this.strokeWidth;

Expand All @@ -100,10 +102,23 @@
// (by copying fillStyle to strokeStyle, since line is stroked, not filled)
var origStrokeStyle = ctx.strokeStyle;
ctx.strokeStyle = this.stroke || ctx.fillStyle;
ctx.stroke();
this._renderStroke(ctx);
ctx.strokeStyle = origStrokeStyle;
},

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderDashedStroke: function(ctx) {
var x = this.width === 1 ? 0 : -this.width / 2,
y = this.height === 1 ? 0 : -this.height / 2;

ctx.beginPath();
fabric.util.drawDashedLine(ctx, x, y, -x, -y, this.strokeDashArray);
ctx.closePath();
},

/**
* Returns complexity of an instance
* @return {Number} complexity
Expand Down
36 changes: 35 additions & 1 deletion src/object.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@
return [
"stroke: ", (this.stroke ? this.stroke : 'none'), "; ",
"stroke-width: ", (this.strokeWidth ? this.strokeWidth : '0'), "; ",
"stroke-dasharray: ", (this.strokeDashArray ? this.strokeDashArray.join(' ') : "; "),
"stroke-dasharray: ", (this.strokeDashArray ? this.strokeDashArray.join(' ') : ''), "; ",
"fill: ", (this.fill ? (this.fill && this.fill.toLive ? 'url(#SVGID_' + this.fill.id + ')' : this.fill) : 'none'), "; ",
"opacity: ", (typeof this.opacity !== 'undefined' ? this.opacity : '1'), ";",
(this.visible ? '' : " visibility: hidden;")
Expand Down Expand Up @@ -637,6 +637,7 @@

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_setShadow: function(ctx) {
if (!this.shadow) return;
Expand All @@ -649,6 +650,7 @@

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_removeShadow: function(ctx) {
ctx.shadowColor = '';
Expand All @@ -657,6 +659,7 @@

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderFill: function(ctx) {
if (!this.fill) return;
Expand All @@ -671,6 +674,37 @@
if (this.fill.toLive) {
ctx.restore();
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
},

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderStroke: function(ctx) {
if (!this.stroke && !this.strokeDashArray) return;

if (this.strokeDashArray) {
// Spec requires the concatenation of two copies the dash list when the number of elements is odd
if (1 & this.strokeDashArray.length) {
this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);
}

if (fabric.StaticCanvas.supports('setLineDash')) {
ctx.setLineDash(this.strokeDashArray);
this._stroke && this._stroke(ctx);
}
else {
this._renderDashedStroke && this._renderDashedStroke(ctx);
}
ctx.stroke();
}
else {
this._stroke ? this._stroke(ctx) : ctx.stroke();
}
this._removeShadow(ctx);
},

/**
Expand Down
9 changes: 3 additions & 6 deletions src/path.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,17 +561,14 @@
this._render(ctx);
this._renderFill(ctx);

this.clipTo && ctx.restore();
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}

if (this.stroke) {
ctx.strokeStyle = this.stroke;
ctx.lineWidth = this.strokeWidth;
ctx.lineCap = ctx.lineJoin = 'round';
ctx.stroke();
this._renderStroke(ctx);
}
this.clipTo && ctx.restore();

this._removeShadow(ctx);

if (!noTransform && this.active) {
Expand Down
3 changes: 2 additions & 1 deletion src/pencil_brush.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@
this.canvas.add(path);
path.setCoords();

this.canvas.contextTop && this.canvas.clearContext(this.canvas.contextTop);
this.canvas.clearContext(this.canvas.contextTop);
this.removeShadowStyles();
this.canvas.renderAll();

// fire event 'path' created
Expand Down
21 changes: 18 additions & 3 deletions src/polygon.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,28 @@
ctx.lineTo(point.x, point.y);
}
this._renderFill(ctx);
this._removeShadow(ctx);
if (this.stroke) {
if (this.stroke || this.strokeDashArray) {
ctx.closePath();
ctx.stroke();
this._renderStroke(ctx);
}
},

/**
* @private
* @param ctx {CanvasRenderingContext2D} context to render on
*/
_renderDashedStroke: function(ctx) {
var p1, p2;

ctx.beginPath();
for (var i = 0, len = this.points.length; i < len; i++) {
p1 = this.points[i];
p2 = this.points[i+1] || this.points[0];
fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray);
}
ctx.closePath();
},

/**
* Returns complexity of an instance
* @return {Number} complexity of this instance
Expand Down
22 changes: 18 additions & 4 deletions src/polyline.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* Constructor
* @param {Array} points array of points
* @param {Object} [options] Options object
* @param {Boolean} Whether points offsetting should be skipped
* @param {Boolean} skipOffset Whether points offsetting should be skipped
* @return {fabric.Polyline} thisArg
*/
initialize: function(points, options, skipOffset) {
Expand All @@ -39,6 +39,7 @@

/**
* @private
* @param {Boolean} skipOffset Whether points offsetting should be skipped
*/
_calcDimensions: function(skipOffset) {
return fabric.Polygon.prototype._calcDimensions.call(this, skipOffset);
Expand Down Expand Up @@ -95,10 +96,23 @@
point = this.points[i];
ctx.lineTo(point.x, point.y);
}

this._renderFill(ctx);
this._removeShadow(ctx);
if (this.stroke) {
ctx.stroke();
this._renderStroke(ctx);
},

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderDashedStroke: function(ctx) {
var p1, p2;

ctx.beginPath();
for (var i = 0, len = this.points.length; i < len; i++) {
p1 = this.points[i];
p2 = this.points[i+1] || p1;
fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray);
}
},

Expand Down
Loading

0 comments on commit f297127

Please sign in to comment.