Refactor brushes

This commit is contained in:
kangax 2013-01-20 17:28:06 +01:00
parent 21ee892c28
commit 8a74303443
6 changed files with 282 additions and 92 deletions

View file

@ -115,8 +115,12 @@ var filesToInclude = [
'src/static_canvas.class.js',
ifSpecifiedInclude('freedrawing', 'src/base_brush.class.js'),
ifSpecifiedInclude('freedrawing', 'src/pencil_brush.class.js'),
ifSpecifiedInclude('freedrawing', 'src/circle_brush.class.js'),
ifSpecifiedInclude('freedrawing', 'src/spray_brush.class.js'),
ifSpecifiedInclude('freedrawing', 'src/pattern_brush.class.js'),
ifSpecifiedInclude('interaction', 'src/canvas.class.js'),

75
src/base_brush.class.js Normal file
View file

@ -0,0 +1,75 @@
/**
* BaseBrush class
* @class fabric.BaseBrush
*/
fabric.BaseBrush = fabric.util.createClass({
/**
* Color of a brush
* @property
* @type String
*/
color: 'rgb(0, 0, 0)',
/**
* Width of a brush
* @property
* @type Number
*/
width: 1,
/**
* Shadow blur of a brush
* @property
* @type Number
*/
shadowBlur: 0,
/**
* Shadow color of a brush
* @property
* @type String
*/
shadowColor: '',
/**
* Shadow offset x of a brush
* @property
* @type Number
*/
shadowOffsetX: 0,
/**
* Shadow offset y of a brush
* @property
* @type Number
*/
shadowOffsetY: 0,
/**
* Sets brush styles
* @method setBrushStyles
*/
setBrushStyles: function() {
var ctx = this.canvas.contextTop;
ctx.strokeStyle = this.color;
ctx.lineWidth = this.width;
ctx.lineCap = ctx.lineJoin = 'round';
},
/**
* Sets brush shadow styles
* @method setShadowStyles
*/
setShadowStyles: function() {
var ctx = this.canvas.contextTop;
if (this.shadowBlur) {
ctx.shadowBlur = this.shadowBlur;
ctx.shadowColor = this.shadowColor || this.color;
ctx.shadowOffsetX = this.shadowOffsetX;
ctx.shadowOffsetY = this.shadowOffsetY;
}
}
});

View file

@ -2,14 +2,7 @@
* CircleBrush class
* @class fabric.CircleBrush
*/
fabric.CircleBrush = fabric.util.createClass( /** @scope fabric.CircleBrush.prototype */ {
/**
* Color of the brush
* @property
* @type String
*/
color: 'rgb(0, 0, 0)',
fabric.CircleBrush = fabric.util.createClass( fabric.BaseBrush, /** @scope fabric.CircleBrush.prototype */ {
/**
* Width of a brush
@ -18,34 +11,6 @@ fabric.CircleBrush = fabric.util.createClass( /** @scope fabric.CircleBrush.prot
*/
width: 10,
/**
* Shadow blur of a pencil
* @property
* @type Number
*/
shadowBlur: 0,
/**
* Shadow color of a pencil
* @property
* @type String
*/
shadowColor: '',
/**
* Shadow offset x of a pencil
* @property
* @type Number
*/
shadowOffsetX: 0,
/**
* Shadow offset y of a pencil
* @property
* @type Number
*/
shadowOffsetY: 0,
/**
* Constructor
* @method initialize

View file

@ -0,0 +1,41 @@
/**
* PatternBrush class
* @class fabric.PatternBrush
* @extends fabric.BaseBrush
*/
fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @scope fabric.PatternBrush.prototype */ {
createPattern: function(patternCanvas) {
var dotWidth = 20,
dotDistance = 5,
patternCtx = patternCanvas.getContext('2d');
patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;
patternCtx.fillStyle = this.color;
patternCtx.beginPath();
patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);
patternCtx.closePath();
patternCtx.fill();
},
/**
* Creates "pattern" instance property
* @method createPattern
*/
getPattern: function() {
var patternCanvas = fabric.document.createElement('canvas');
this.createPattern(patternCanvas);
return this.canvas.contextTop.createPattern(patternCanvas, 'repeat');
},
/**
* Sets brush styles
* @method setBrushStyles
*/
setBrushStyles: function() {
this.callSuper('setBrushStyles');
this.canvas.contextTop.strokeStyle = this.getPattern();
}
});

View file

@ -6,50 +6,9 @@
/**
* PencilBrush class
* @class fabric.PencilBrush
* @extends fabric.BaseBrush
*/
fabric.PencilBrush = fabric.util.createClass( /** @scope fabric.PencilBrush.prototype */ {
/**
* Color of the pencil
* @property
* @type String
*/
color: 'rgb(0, 0, 0)',
/**
* Width of a pencil
* @property
* @type Number
*/
width: 1,
/**
* Shadow blur of a pencil
* @property
* @type Number
*/
shadowBlur: 0,
/**
* Shadow color of a pencil
* @property
* @type String
*/
shadowColor: '',
/**
* Shadow offset x of a pencil
* @property
* @type Number
*/
shadowOffsetX: 0,
/**
* Shadow offset y of a pencil
* @property
* @type Number
*/
shadowOffsetY: 0,
fabric.PencilBrush = fabric.util.createClass( fabric.BaseBrush, /** @scope fabric.PencilBrush.prototype */ {
/**
* Constructor
@ -126,19 +85,8 @@
_reset: function() {
this._points.length = 0;
var ctx = this.canvas.contextTop;
ctx.strokeStyle = this.color;
ctx.lineWidth = this.width;
if (this.shadowBlur) {
ctx.shadowBlur = this.shadowBlur;
ctx.shadowColor = this.shadowColor || this.color;
ctx.shadowOffsetX = this.shadowOffsetX;
ctx.shadowOffsetY = this.shadowOffsetY;
}
ctx.lineCap = ctx.lineJoin = 'round';
this.setBrushStyles();
this.setShadowStyles();
},
/**

157
src/spray_brush.class.js Normal file
View file

@ -0,0 +1,157 @@
/**
* SprayBrush class
* @class fabric.SprayBrush
*/
fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @scope fabric.SprayBrush.prototype */ {
/**
* Width of a spray
* @property
* @type Number
*/
width: 10,
/**
* Density of a spray (number of dots per chunk)
* @property
* @type Number
*/
density: 20,
/**
* Width of spray dots
* @property
* @type Number
*/
dotWidth: 1,
/**
* Width variance of spray dots
* @property
* @type Number
*/
dotWidthVariance: 1,
/**
* Whether opacity of a dot should be random
* @property
* @type Boolean
*/
randomOpacity: false,
/**
* Constructor
* @method initialize
* @param {fabric.Canvas} canvas
* @return {fabric.SprayBrush} Instance of a spray brush
*/
initialize: function(canvas) {
this.canvas = canvas;
this.sprayChunks = [ ];
},
/**
* @method onMouseDown
* @param {Object} pointer
*/
onMouseDown: function(pointer) {
this.sprayChunks.length = 0;
this.canvas.clearContext(this.canvas.contextTop);
this.setShadowStyles();
this.addSprayChunk(pointer);
this.render();
},
/**
* @method onMouseMove
* @param {Object} pointer
*/
onMouseMove: function(pointer) {
this.addSprayChunk(pointer);
this.render();
},
/**
* @method onMouseUp
*/
onMouseUp: function() {
var originalRenderOnAddition = this.canvas.renderOnAddition;
this.canvas.renderOnAddition = false;
for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {
var sprayChunk = this.sprayChunks[i];
for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {
var rect = new fabric.Rect({
width: sprayChunk[j].width,
height: sprayChunk[j].width,
left: sprayChunk[j].x + 1,
top: sprayChunk[j].y + 1,
fill: this.color
});
this.canvas.add(rect);
}
}
this.canvas.renderOnAddition = originalRenderOnAddition;
this.canvas.clearContext(this.canvas.contextTop);
this.canvas.renderAll();
},
/**
* @method render
*/
render: function() {
var ctx = this.canvas.contextTop;
ctx.fillStyle = this.color;
ctx.save();
for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) {
var point = this.sprayChunkPoints[i];
if (typeof point.opacity !== 'undefined') {
ctx.globalAlpha = point.opacity;
}
ctx.fillRect(point.x, point.y, point.width, point.width);
}
ctx.restore();
},
/**
* @method addSprayChunk
* @param {Object} pointer
*/
addSprayChunk: function(pointer) {
this.sprayChunkPoints = [ ];
var x, y, width, radius = this.width / 2;
for (var i = 0; i < this.density; i++) {
x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);
y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);
if (this.dotWidthVariance) {
width = fabric.util.getRandomInt(
// bottom clamp width to 1
Math.max(1, this.dotWidth - this.dotWidthVariance),
this.dotWidth + this.dotWidthVariance);
}
else {
width = this.dotWidth;
}
var point = { x: x, y: y, width: width };
if (this.randomOpacity) {
point.opacity = fabric.util.getRandomInt(0, 100) / 100;
}
this.sprayChunkPoints.push(point);
}
this.sprayChunks.push(this.sprayChunkPoints);
}
});