2024-03-15 09:21:17 +08:00
/ * *
* fabric . brushes - A collection of brushes for fabric . js ( version 4 and up ) .
*
* Made by Arjan Haverkamp , https : //www.webgear.nl
* Copyright 2021 Arjan Haverkamp
* MIT Licensed
* @ version 1.0 - 2021 - 06 - 02
* @ url https : //github.com/av01d/fabric-brushes
*
* Inspiration sources :
* - https : //github.com/tennisonchan/fabric-brush
* - https : //mrdoob.com/projects/harmony/
* - http : //perfectionkills.com/exploring-canvas-drawing-techniques/
* /
( function ( fabric ) {
/ * *
* Trim a canvas . Returns the left - top coordinate where trimming began .
* @ param { canvas } canvas A canvas element to trim . This element will be trimmed ( reference ) .
* @ returns { Object } Left - top coordinate of trimmed area . Example : { x : 65 , y : 104 }
* @ see : https : //stackoverflow.com/a/22267731/3360038
* /
fabric . util . trimCanvas = function ( canvas ) {
var ctx = canvas . getContext ( '2d' ) ,
w = canvas . width ,
h = canvas . height ,
pix = { x : [ ] , y : [ ] } , n ,
imageData = ctx . getImageData ( 0 , 0 , w , h ) ,
fn = function ( a , b ) { return a - b } ;
for ( var y = 0 ; y < h ; y ++ ) {
for ( var x = 0 ; x < w ; x ++ ) {
if ( imageData . data [ ( ( y * w + x ) * 4 ) + 3 ] > 0 ) {
pix . x . push ( x ) ;
pix . y . push ( y ) ;
}
}
}
pix . x . sort ( fn ) ;
pix . y . sort ( fn ) ;
n = pix . x . length - 1 ;
//if (n == -1) {
// // Nothing to trim... empty canvas?
//}
w = pix . x [ n ] - pix . x [ 0 ] ;
h = pix . y [ n ] - pix . y [ 0 ] ;
if ( ! w ) {
return
}
var cut = ctx . getImageData ( pix . x [ 0 ] , pix . y [ 0 ] , w , h ) ;
canvas . width = w ;
canvas . height = h ;
ctx . putImageData ( cut , 0 , 0 ) ;
return { x : pix . x [ 0 ] , y : pix . y [ 0 ] } ;
}
/ * *
* Extract r , g , b , a components from any valid color .
* Returns { undefined } when color cannot be parsed .
*
* @ param { number } color Any color string ( named , hex , rgb , rgba )
* @ returns { ( Array | undefined ) } Example : [ 0 , 128 , 255 , 1 ]
* @ see https : //gist.github.com/oriadam/396a4beaaad465ca921618f2f2444d49
* /
fabric . util . colorValues = function ( color ) {
if ( ! color ) { return ; }
if ( color . toLowerCase ( ) === 'transparent' ) { return [ 0 , 0 , 0 , 0 ] ; }
if ( color [ 0 ] === '#' ) {
if ( color . length < 7 ) {
// convert #RGB and #RGBA to #RRGGBB and #RRGGBBAA
color = '#' + color [ 1 ] + color [ 1 ] + color [ 2 ] + color [ 2 ] + color [ 3 ] + color [ 3 ] + ( color . length > 4 ? color [ 4 ] + color [ 4 ] : '' ) ;
}
return [ parseInt ( color . substr ( 1 , 2 ) , 16 ) ,
parseInt ( color . substr ( 3 , 2 ) , 16 ) ,
parseInt ( color . substr ( 5 , 2 ) , 16 ) ,
color . length > 7 ? parseInt ( color . substr ( 7 , 2 ) , 16 ) / 255 : 1 ] ;
}
if ( color . indexOf ( 'rgb' ) === - 1 ) {
// convert named colors
var tempElem = document . body . appendChild ( document . createElement ( 'fictum' ) ) ; // intentionally use unknown tag to lower chances of css rule override with !important
var flag = 'rgb(1, 2, 3)' ; // this flag tested on chrome 59, ff 53, ie9, ie10, ie11, edge 14
tempElem . style . color = flag ;
if ( tempElem . style . color !== flag ) {
return ; // color set failed - some monstrous css rule is probably taking over the color of our object
}
tempElem . style . color = color ;
if ( tempElem . style . color === flag || tempElem . style . color === '' ) {
return ; // color parse failed
}
color = getComputedStyle ( tempElem ) . color ;
document . body . removeChild ( tempElem ) ;
}
if ( color . indexOf ( 'rgb' ) === 0 ) {
if ( color . indexOf ( 'rgba' ) === - 1 ) {
color += ',1' ; // convert 'rgb(R,G,B)' to 'rgb(R,G,B)A' which looks awful but will pass the regxep below
}
return color . match ( /[\.\d]+/g ) . map ( function ( a ) {
return + a
} ) ;
}
}
fabric . Point . prototype . angleBetween = function ( that ) {
return Math . atan2 ( this . x - that . x , this . y - that . y ) ;
} ;
fabric . Point . prototype . normalize = function ( thickness ) {
if ( null === thickness || undefined === thickness ) {
thickness = 1 ;
}
var length = this . distanceFrom ( { x : 0 , y : 0 } ) ;
if ( length > 0 ) {
this . x = this . x / length * thickness ;
this . y = this . y / length * thickness ;
}
return this ;
} ;
/ * *
* Convert a brush drawing on the upperCanvas to an image on the fabric canvas .
* This makes the drawing editable , it can be moved , rotated , scaled , skewed etc .
* /
2024-11-22 09:20:25 +08:00
fabric . BaseBrush . prototype . convertToPath = function ( ) {
var pixelRatio = this . canvas . getRetinaScaling ( ) ,
c = fabric . util . copyCanvasElement ( this . canvas . upperCanvasEl ) ,
xy = fabric . util . trimCanvas ( c ) ,
path = this . _points . map ( arr => {
arr [ 1 ] = arr [ 1 ] / this . canvas . getZoom ( )
arr [ 2 ] = arr [ 2 ] / this . canvas . getZoom ( )
return arr . join ( ' ' )
} ) . join ( ' ' ) ,
pathElemetn = new fabric . Path ( path ) ;
if ( ! xy ) {
return
}
let pointerX = this . canvas . viewportTransform [ 4 ] ;
let pointerY = this . canvas . viewportTransform [ 5 ] ;
pathElemetn . set ( {
strokeDashArray : [ this . _width * 3 , this . _width * 3 ] ,
strokeWidth : this . _width ,
stroke : 'black' ,
fill : 'transparent' ,
2025-01-16 09:47:28 +08:00
custom : {
dashed : true
} ,
2024-11-22 09:20:25 +08:00
} ) . setCoords ( ) ;
let group = new fabric . Group ( [ pathElemetn ] , {
left : ( ( xy . x ) / pixelRatio - pointerX ) / this . canvas . getZoom ( ) ,
top : ( ( xy . y ) / pixelRatio - pointerY ) / this . canvas . getZoom ( ) ,
custom : {
dashed : true
2025-01-16 09:47:28 +08:00
} ,
2024-11-22 09:20:25 +08:00
} )
this . canvas . add ( group ) . clearContext ( this . canvas . contextTop ) ;
this . canvas . clearContext ( this . canvas . contextTop ) ;
}
2024-03-15 09:21:17 +08:00
fabric . BaseBrush . prototype . convertToImg = function ( ) {
var pixelRatio = this . canvas . getRetinaScaling ( ) ,
c = fabric . util . copyCanvasElement ( this . canvas . upperCanvasEl ) ,
xy = fabric . util . trimCanvas ( c ) ,
img = new fabric . Image ( c ) ;
if ( ! xy ) {
return
}
2024-10-14 16:42:28 +08:00
let pointerX = this . canvas . viewportTransform [ 4 ] ;
2024-11-22 09:20:25 +08:00
let pointerY = this . canvas . viewportTransform [ 5 ] ;
img . set ( {
left : ( ( xy . x ) / pixelRatio - pointerX ) / this . canvas . getZoom ( ) ,
top : ( ( xy . y ) / pixelRatio - pointerY ) / this . canvas . getZoom ( ) ,
'scaleX' : 1 / pixelRatio / this . canvas . getZoom ( ) ,
'scaleY' : 1 / pixelRatio / this . canvas . getZoom ( )
} ) . setCoords ( ) ;
2024-03-15 09:21:17 +08:00
this . canvas . add ( img ) . clearContext ( this . canvas . contextTop ) ;
this . canvas . clearContext ( this . canvas . contextTop ) ;
}
fabric . util . getRandom = function ( max , min ) {
min = min ? min : 0 ;
return Math . random ( ) * ( ( max ? max : 1 ) - min ) + min ;
} ;
fabric . util . clamp = function ( n , max , min ) {
if ( typeof min !== 'number' ) { min = 0 ; }
return n > max ? max : n < min ? min : n ;
} ;
fabric . Stroke = fabric . util . createClass ( fabric . Object , {
color : null ,
inkAmount : null ,
lineWidth : null ,
_point : null ,
_lastPoint : null ,
_currentLineWidth : null ,
initialize : function ( ctx , pointer , range , color , lineWidth , inkAmount ) {
var rx = fabric . util . getRandom ( range ) ,
c = fabric . util . getRandom ( Math . PI * 2 ) ,
c0 = fabric . util . getRandom ( Math . PI * 2 ) ,
x0 = rx * Math . sin ( c0 ) ,
y0 = rx / 2 * Math . cos ( c0 ) ,
cos = Math . cos ( c ) ,
sin = Math . sin ( c ) ;
this . ctx = ctx ;
this . color = color ;
this . _point = new fabric . Point ( pointer . x + x0 * cos - y0 * sin , pointer . y + x0 * sin + y0 * cos ) ;
this . lineWidth = lineWidth ;
this . inkAmount = inkAmount ;
this . _currentLineWidth = lineWidth ;
ctx . lineCap = 'round' ;
} ,
update : function ( pointer , subtractPoint , distance ) {
this . _lastPoint = fabric . util . object . clone ( this . _point ) ;
this . _point = this . _point . addEquals ( { x : subtractPoint . x , y : subtractPoint . y } ) ;
var n = this . inkAmount / ( distance + 1 ) ,
per = ( n > 0.3 ? 0.2 : n < 0 ? 0 : n ) ;
this . _currentLineWidth = this . lineWidth * per ;
} ,
draw : function ( ) {
var ctx = this . ctx ;
ctx . save ( ) ;
this . line ( ctx , this . _lastPoint , this . _point , this . color , this . _currentLineWidth ) ;
ctx . restore ( ) ;
} ,
line : function ( ctx , point1 , point2 , color , lineWidth ) {
ctx . strokeStyle = color ;
ctx . lineWidth = lineWidth ;
ctx . beginPath ( ) ;
ctx . moveTo ( point1 . x , point1 . y ) ;
ctx . lineTo ( point2 . x , point2 . y ) ;
ctx . stroke ( ) ;
}
} ) ;
/ * *
* CrayonBrush
* Based on code by Tennison Chan .
* /
fabric . CrayonBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 0.6 ,
width : 30 ,
_baseWidth : 15 ,
_inkAmount : 10 ,
_latestStrokeLength : 0 ,
_point : null ,
_sep : 3 ,
_size : 0 ,
_latest : null ,
_drawn : false ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . _baseWidth = this . width / 2
this . _point = new fabric . Point ( 0 , 0 ) ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . canvas . contextTop . globalAlpha = this . opacity ;
this . _size = this . width / 2 + this . _baseWidth ;
this . _drawn = false ;
this . set ( pointer ) ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . update ( pointer ) ;
this . draw ( this . canvas . contextTop ) ;
} ,
onMouseUp : function ( ) {
if ( this . _drawn ) {
this . convertToImg ( ) ;
}
this . _latest = null ;
this . _latestStrokeLength = 0 ;
this . canvas . contextTop . globalAlpha = 1 ;
} ,
set : function ( p ) {
if ( this . _latest ) {
this . _latest . setFromPoint ( this . _point ) ;
} else {
this . _latest = new fabric . Point ( p . x , p . y ) ;
}
fabric . Point . prototype . setFromPoint . call ( this . _point , p ) ;
} ,
update : function ( p ) {
this . set ( p ) ;
this . _latestStrokeLength = this . _point . subtract ( this . _latest ) . distanceFrom ( { x : 0 , y : 0 } ) ;
} ,
draw : function ( ctx ) {
var i , j , p , r , c , x , y , w , h , v , s , stepNum , dotSize , dotNum , range ;
v = this . _point . subtract ( this . _latest ) ;
s = Math . ceil ( this . _size / 2 ) ;
stepNum = Math . floor ( v . distanceFrom ( { x : 0 , y : 0 } ) / s ) + 1 ;
v . normalize ( s ) ;
dotSize = this . _sep * fabric . util . clamp ( this . _inkAmount / this . _latestStrokeLength * 3 , 1 , 0.5 ) ;
dotNum = Math . ceil ( this . _size * this . _sep ) ;
range = this . _size / 2 ;
ctx . save ( ) ;
ctx . fillStyle = this . color ;
ctx . beginPath ( ) ;
for ( i = 0 ; i < dotNum ; i ++ ) {
for ( j = 0 ; j < stepNum ; j ++ ) {
p = this . _latest . add ( v . multiply ( j ) ) ;
r = fabric . util . getRandom ( range ) ;
c = fabric . util . getRandom ( Math . PI * 2 ) ;
w = fabric . util . getRandom ( dotSize , dotSize / 2 ) ;
h = fabric . util . getRandom ( dotSize , dotSize / 2 ) ;
x = p . x + r * Math . sin ( c ) - w / 2 ;
y = p . y + r * Math . cos ( c ) - h / 2 ;
ctx . rect ( x , y , w , h ) ;
}
}
ctx . fill ( ) ;
ctx . restore ( ) ;
this . _drawn = true ;
} ,
_render : function ( ) { }
} ) ; // End CrayonBrush
/ * *
* FurBrush
* Based on code by Mr . Doob .
* /
fabric . FurBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 1 ,
_count : 0 ,
_points : [ ] ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || 1 ;
} ,
onMouseDown : function ( pointer ) {
this . _points = [ pointer ] ;
this . _count = 0 ;
var ctx = this . canvas . contextTop ,
color = fabric . util . colorValues ( this . color ) ;
ctx . strokeStyle = 'rgba(' + color [ 0 ] + ',' + color [ 1 ] + ',' + color [ 2 ] + ',' + ( 0.1 * this . opacity ) + ')' ;
ctx . lineWidth = this . width ;
this . _points . push ( pointer ) ;
} ,
onMouseMove : function ( pointer ) {
this . _points . push ( pointer ) ;
var i , dx , dy , d ,
ctx = this . canvas . contextTop ,
points = this . _points ,
lastPoint = points [ points . length - 2 ] ;
ctx . beginPath ( ) ;
ctx . moveTo ( lastPoint . x , lastPoint . y ) ;
ctx . lineTo ( pointer . x , pointer . y ) ;
ctx . stroke ( ) ;
for ( i = 0 ; i < this . _points . length ; i ++ ) {
dx = this . _points [ i ] . x - this . _points [ this . _count ] . x ;
dy = this . _points [ i ] . y - this . _points [ this . _count ] . y ;
d = dx * dx + dy * dy ;
if ( d < 2000 && Math . random ( ) > d / 2000 ) {
ctx . beginPath ( ) ;
ctx . moveTo ( pointer . x + ( dx * 0.5 ) , pointer . y + ( dy * 0.5 ) ) ;
ctx . lineTo ( pointer . x - ( dx * 0.5 ) , pointer . y - ( dy * 0.5 ) ) ;
ctx . stroke ( ) ;
}
}
this . _count ++ ;
} ,
onMouseUp : function ( pointer ) {
if ( this . _count > 0 ) {
this . convertToImg ( ) ;
}
} ,
_render : function ( ) { }
} ) ; // End FurBrush
/ * *
* InkBrush
* Based on code by Tennison Chan .
* /
fabric . InkBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 30 ,
_baseWidth : 15 ,
_inkAmount : 7 ,
_lastPoint : null ,
_point : null ,
_range : 10 ,
_strokes : null ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . _baseWidth = this . width
this . _point = new fabric . Point ( ) ;
} ,
_render : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
var len , i , point = this . setPointer ( pointer ) ,
subtractPoint = point . subtract ( this . _lastPoint ) ,
distance = point . distanceFrom ( this . _lastPoint ) ,
stroke ;
for ( i = 0 , len = this . _strokes . length ; i < len ; i ++ ) {
stroke = this . _strokes [ i ] ;
stroke . update ( point , subtractPoint , distance ) ;
stroke . draw ( ) ;
}
if ( distance > 30 ) {
2024-11-22 09:20:25 +08:00
this . drawSplash ( point , this . _inkAmount ) ;
2024-03-15 09:21:17 +08:00
}
} ,
onMouseDown : function ( pointer ) {
this . canvas . contextTop . globalAlpha = this . opacity ;
this . _resetTip ( pointer ) ;
} ,
onMouseMove : function ( pointer ) {
if ( this . canvas . _isCurrentlyDrawing ) {
this . _render ( pointer ) ;
}
} ,
onMouseUp : function ( ) {
this . convertToImg ( ) ;
this . canvas . contextTop . globalAlpha = 1 ;
} ,
hexToRgba : function ( hex , alpha ) {
} ,
drawSplash : function ( pointer , maxSize ) {
var c , r , i , point ,
ctx = this . canvas . contextTop ,
num = fabric . util . getRandom ( 12 ) ,
range = maxSize * 10 ,
color = this . color ;
ctx . save ( ) ;
for ( i = 0 ; i < num ; i ++ ) {
r = fabric . util . getRandom ( range , 1 ) ;
c = fabric . util . getRandom ( Math . PI * 2 ) ;
point = new fabric . Point ( pointer . x + r * Math . sin ( c ) , pointer . y + r * Math . cos ( c ) ) ;
ctx . fillStyle = color ;
ctx . beginPath ( ) ;
ctx . arc ( point . x , point . y , fabric . util . getRandom ( maxSize ) / 2 , 0 , Math . PI * 2 , false ) ;
ctx . fill ( ) ;
}
ctx . restore ( ) ;
} ,
setPointer : function ( pointer ) {
var point = new fabric . Point ( pointer . x , pointer . y ) ;
this . _lastPoint = fabric . util . object . clone ( this . _point ) ;
this . _point = point ;
return point ;
} ,
_resetTip : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
var len , i , point = this . setPointer ( pointer ) ;
2024-03-20 13:34:07 +08:00
2024-03-15 09:21:17 +08:00
this . _strokes = [ ] ;
this . size = this . width ;
this . _range = this . size / 2 ;
for ( i = 0 , len = this . size ; i < len ; i ++ ) {
this . _strokes [ i ] = new fabric . Stroke ( this . canvas . contextTop , point , this . _range , this . color , this . width + 10 , this . _inkAmount ) ;
}
}
} ) ; // End InkBrush
/ * *
* LongfurBrush
* Based on code by Mr . Doob .
* /
fabric . LongfurBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 1 ,
_count : 0 ,
_points : [ ] ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || 1 ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points = [ pointer ] ;
this . _count = 0 ;
var ctx = this . canvas . contextTop ,
color = fabric . util . colorValues ( this . color ) ;
//ctx.globalCompositeOperation = 'source-over';
ctx . strokeStyle = 'rgba(' + color [ 0 ] + ',' + color [ 1 ] + ',' + color [ 2 ] + ',' + ( 0.05 * this . opacity ) + ')' ;
ctx . lineWidth = this . width ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points . push ( pointer ) ;
var i , dx , dy , d , size ,
ctx = this . canvas . contextTop ,
points = this . _points ;
for ( i = 0 ; i < this . _points . length ; i ++ ) {
size = - Math . random ( ) ;
dx = this . _points [ i ] . x - this . _points [ this . _count ] . x ;
dy = this . _points [ i ] . y - this . _points [ this . _count ] . y ;
d = dx * dx + dy * dy ;
if ( d < 1000 && Math . random ( ) > d / 1000 ) {
ctx . beginPath ( ) ;
ctx . moveTo ( this . _points [ this . _count ] . x + ( dx * size ) , this . _points [ this . _count ] . y + ( dy * size ) ) ;
ctx . lineTo ( this . _points [ i ] . x - ( dx * size ) + Math . random ( ) * 2 , this . _points [ i ] . y - ( dy * size ) + Math . random ( ) * 2 ) ;
ctx . stroke ( ) ;
}
}
this . _count ++ ;
} ,
onMouseUp : function ( pointer ) {
if ( this . _count > 0 ) {
this . convertToImg ( ) ;
}
} ,
_render : function ( ) { }
} ) ; // End LongfurBrush
/ * *
* WritingBrush
* Based on code by Tennison Chan .
* /
fabric . WritingBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 30 ,
_baseWidth : 15 ,
_lastPoint : null ,
_lineWidth : 2 ,
_point : null ,
_size : 0 ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . _baseWidth = this . width ;
this . canvas . contextTop . globalAlpha = this . opacity ;
this . _point = new fabric . Point ( ) ;
this . canvas . contextTop . lineJoin = 'round' ;
this . canvas . contextTop . lineCap = 'round' ;
} ,
_render : function ( pointer ) {
var ctx , lineWidthDiff , i , len ;
ctx = this . canvas . contextTop ;
ctx . beginPath ( ) ;
// let num = this._size / this._lineWidth / 2 / 1.2
let num = this . width / 1.25 / 2
for ( i = 0 , len = this . width / 1.25 ; i < len ; i ++ ) {
// for(i = 0, len = (this._size / this._lineWidth) / 1.2; i < len; i++) {
lineWidthDiff = ( this . _lineWidth - 1 ) * i ;
ctx . globalAlpha = 0.8 * this . opacity ;
ctx . moveTo ( this . _lastPoint . x - lineWidthDiff + num , this . _lastPoint . y + lineWidthDiff - num ) ;
ctx . lineTo ( pointer . x - lineWidthDiff + num , pointer . y + lineWidthDiff - num ) ;
ctx . stroke ( ) ;
}
this . _lastPoint = new fabric . Point ( pointer . x , pointer . y ) ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = pointer ;
this . canvas . contextTop . strokeStyle = this . color ;
this . canvas . contextTop . lineWidth = this . _lineWidth ;
this . _size = this . width + this . _baseWidth ;
} ,
onMouseMove : function ( pointer ) {
if ( this . canvas . _isCurrentlyDrawing ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _render ( pointer ) ;
}
} ,
onMouseUp : function ( ) {
this . canvas . contextTop . globalAlpha = this . opacity ;
this . canvas . contextTop . globalAlpha = 1 ;
this . convertToImg ( ) ;
}
} ) ; // End WritingBrush
/ * *
* MarkerBrush
* Based on code by Tennison Chan .
* /
fabric . MarkerBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 30 ,
_baseWidth : 15 ,
_lastPoint : null ,
_lineWidth : 2 ,
_point : null ,
_size : 0 ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . _baseWidth = this . width ;
this . canvas . contextTop . globalAlpha = this . opacity ;
this . _point = new fabric . Point ( ) ;
this . canvas . contextTop . lineJoin = 'round' ;
this . canvas . contextTop . lineCap = 'round' ;
} ,
_render : function ( pointer ) {
var ctx , lineWidthDiff , i , len ;
ctx = this . canvas . contextTop ;
ctx . beginPath ( ) ;
let num = this . width / 1.25 / 2
for ( i = 0 , len = this . width / 1.25 ; i < len ; i ++ ) {
lineWidthDiff = ( this . _lineWidth - 1 ) * i ;
ctx . globalAlpha = 0.8 * this . opacity ;
ctx . moveTo ( this . _lastPoint . x + lineWidthDiff - num , ( this . _lastPoint . y + lineWidthDiff - num ) ) ;
ctx . lineTo ( pointer . x + lineWidthDiff - num , pointer . y + lineWidthDiff - num ) ;
ctx . stroke ( ) ;
}
this . _lastPoint = new fabric . Point ( pointer . x , pointer . y ) ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = pointer ;
this . canvas . contextTop . strokeStyle = this . color ;
this . canvas . contextTop . lineWidth = this . _lineWidth ;
this . _size = this . width + this . _baseWidth / 2 ;
} ,
onMouseMove : function ( pointer ) {
if ( this . canvas . _isCurrentlyDrawing ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _render ( pointer ) ;
}
} ,
onMouseUp : function ( ) {
this . canvas . contextTop . globalAlpha = this . opacity ;
this . canvas . contextTop . globalAlpha = 1 ;
this . convertToImg ( ) ;
}
} ) ; // End MarkerBrush
2024-11-22 09:20:25 +08:00
/ * *
* test
* Based on code by Tennison Chan .
* /
fabric . Test = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
_points : [ ] ,
_width : 2 ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . _width = opt . _width || this . _width ;
this . color = opt . color || this . color ;
} ,
_render : function ( pointer ) {
var ctx , lineWidthDiff , i , len ;
ctx = this . canvas . contextTop ;
this . _points . push ( [ 'L' , pointer . x , pointer . y ] ) ;
// if(this._points.length % 10 < 5){
let points = this . _points
ctx . beginPath ( ) ;
ctx . moveTo ( points [ points . length - 2 ] [ 1 ] , points [ points . length - 2 ] [ 2 ] ) ;
ctx . lineTo ( points [ points . length - 1 ] [ 1 ] , points [ points . length - 1 ] [ 2 ] ) ;
ctx . stroke ( ) ;
// }
} ,
onMouseDown : function ( pointer ) {
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
this . _points = [ ]
this . _points . push ( [ 'M' , pointer . x , pointer . y ] ) ;
var ctx = this . canvas . contextTop ;
ctx . strokeStyle = 'rgba(' + 0 + ',' + 0 + ',' + 0 + ',' + 1 + ')' ;
ctx . lineWidth = this . _width * this . canvas . getZoom ( ) ;
ctx . lineJoin = ctx . lineCap = 'round' ;
} ,
onMouseMove : function ( pointer ) {
if ( this . canvas . _isCurrentlyDrawing ) {
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
this . _render ( pointer ) ;
}
} ,
onMouseUp : function ( ) {
this . _points . push ( [ 'Z' ] ) ;
this . convertToPath ( ) ;
}
} ) ; // End test
2024-03-15 09:21:17 +08:00
/ * *
* MarkerBrush
* Based on code by Tennison Chan .
* /
fabric . MarkerBrush1 = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 30 ,
content : 0 ,
_baseWidth : 15 ,
_lastPoint : null ,
_lineWidth : 2 ,
_point : null ,
_size : 0 ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . _baseWidth = this . width ;
this . content = opt . content || canvas . width / 2 ;
this . canvas . contextTop . globalAlpha = this . opacity ;
this . _point = new fabric . Point ( ) ;
this . canvas . contextTop . lineJoin = 'round' ;
this . canvas . contextTop . lineCap = 'round' ;
} ,
_render : function ( pointer ) {
var ctx , lineWidthDiff , i , len ;
ctx = this . canvas . contextTop ;
ctx . beginPath ( ) ;
for ( i = 0 , len = ( this . _size / this . _lineWidth ) / 2 ; i < len ; i ++ ) {
lineWidthDiff = ( this . _lineWidth - 1 ) * i ;
let half = this . canvas . width / 2
ctx . globalAlpha = 0.8 * this . opacity ;
ctx . moveTo ( this . _lastPoint . x , this . _lastPoint . y ) ;
let x = content > this . _lastPoint . x ? content - this . _lastPoint . x + content : content * 2 - this . _lastPoint . x
ctx . lineTo ( x , this . _lastPoint . y ) ;
// ctx.lineTo(pointer.y + lineWidthDiff,pointer.x + lineWidthDiff);
ctx . stroke ( ) ;
}
this . _lastPoint = new fabric . Point ( pointer . x , pointer . y ) ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = pointer ;
this . canvas . contextTop . strokeStyle = this . color ;
this . canvas . contextTop . lineWidth = this . _lineWidth ;
this . _size = this . width + this . _baseWidth ;
} ,
onMouseMove : function ( pointer ) {
if ( this . canvas . _isCurrentlyDrawing ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _render ( pointer ) ;
}
} ,
onMouseUp : function ( ) {
this . canvas . contextTop . globalAlpha = this . opacity ;
this . canvas . contextTop . globalAlpha = 1 ;
this . convertToImg ( ) ;
}
} ) ; // End MarkerBrush
2024-03-20 13:34:07 +08:00
/ * *
* PenBrush
* Based on code by Tennison Chan .
* /
fabric . PenBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 30 ,
_baseWidth : 15 ,
_lastPoint : null ,
_lineWidth : 2 ,
_point : null ,
_size : 0 ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . _baseWidth = this . width ;
this . canvas . contextTop . globalAlpha = this . opacity ;
this . _point = new fabric . Point ( ) ;
this . canvas . contextTop . lineJoin = 'round' ;
this . canvas . contextTop . lineCap = 'round' ;
} ,
_render : function ( pointer ) {
var ctx , lineWidthDiff , i , len ;
ctx = this . canvas . contextTop ;
ctx . beginPath ( ) ;
// let num = this._size / this._lineWidth / 2 / 1.2
let num = this . width / 1.25 / 2
for ( i = 0 , len = this . width / 1.25 ; i < len ; i ++ ) {
// for(i = 0, len = (this._size / this._lineWidth) / 1.2; i < len; i++) {
var randomNum = Math . random ( ) * ( 0.6 - 0.2 ) + 0.2 ;
var color = this . color . replace ( /1(?=\))/ , randomNum ) ;
this . canvas . contextTop . strokeStyle = color ;
lineWidthDiff = ( this . _lineWidth - 1 ) * i ;
ctx . globalAlpha = 0.8 * this . opacity ;
ctx . moveTo ( this . _lastPoint . x , this . _lastPoint . y + lineWidthDiff - num ) ;
ctx . lineTo ( pointer . x , pointer . y + lineWidthDiff - num ) ;
ctx . stroke ( ) ;
}
this . _lastPoint = new fabric . Point ( pointer . x , pointer . y ) ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-20 13:34:07 +08:00
this . _lastPoint = pointer ;
this . canvas . contextTop . lineWidth = this . _lineWidth ;
this . _size = this . width + this . _baseWidth ;
} ,
onMouseMove : function ( pointer ) {
if ( this . canvas . _isCurrentlyDrawing ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-20 13:34:07 +08:00
this . _render ( pointer ) ;
}
} ,
onMouseUp : function ( ) {
this . canvas . contextTop . globalAlpha = this . opacity ;
this . canvas . contextTop . globalAlpha = 1 ;
this . convertToImg ( ) ;
}
} ) ; // End PenBrush
2024-03-15 09:21:17 +08:00
/ * *
* RibbonBrush
* Based on code by Mr . Doob .
* /
fabric . RibbonBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 1 ,
_nrPainters : 50 ,
_painters : [ ] ,
_lastPoint : null ,
_interval : null ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . _nrPainters = opt . _nrPainters || this . _nrPainters ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
for ( var i = 0 ; i < this . _nrPainters ; i ++ ) {
this . _painters . push ( { dx : this . canvas . width / 2 , dy : this . canvas . height / 2 , ax : 0 , ay : 0 , div : . 1 , ease : Math . random ( ) * . 2 + . 6 } ) ;
}
} ,
update : function ( ) {
var ctx = this . canvas . contextTop , painters = this . _painters ;
for ( var i = 0 ; i < painters . length ; i ++ ) {
ctx . beginPath ( ) ;
ctx . moveTo ( painters [ i ] . dx , painters [ i ] . dy ) ;
painters [ i ] . dx -= painters [ i ] . ax = ( painters [ i ] . ax + ( painters [ i ] . dx - this . _lastPoint . x ) * painters [ i ] . div ) * painters [ i ] . ease ;
painters [ i ] . dy -= painters [ i ] . ay = ( painters [ i ] . ay + ( painters [ i ] . dy - this . _lastPoint . y ) * painters [ i ] . div ) * painters [ i ] . ease ;
ctx . lineTo ( painters [ i ] . dx , painters [ i ] . dy ) ;
ctx . stroke ( ) ;
}
} ,
onMouseDown : function ( pointer ) {
var ctx = this . canvas . contextTop ,
color = fabric . util . colorValues ( this . color ) ;
this . _painters = [ ] ;
for ( var i = 0 ; i < this . _nrPainters ; i ++ ) {
this . _painters . push ( { dx : this . canvas . width / 2 , dy : this . canvas . height / 2 , ax : 0 , ay : 0 , div : . 1 , ease : Math . random ( ) * . 2 + . 6 } ) ;
}
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = pointer ;
//ctx.globalCompositeOperation = 'source-over';
ctx . strokeStyle = 'rgba(' + color [ 0 ] + ',' + color [ 1 ] + ',' + color [ 2 ] + ',' + ( 0.05 * this . opacity ) + ')' ;
ctx . lineWidth = this . width ;
for ( var i = 0 ; i < this . _nrPainters ; i ++ ) {
this . _painters [ i ] . dx = pointer . x ;
this . _painters [ i ] . dy = pointer . y ;
}
var self = this ;
this . _interval = setInterval ( function ( ) { self . update ( ) } , 1000 / 60 ) ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = pointer ;
} ,
onMouseUp : function ( pointer ) {
clearInterval ( this . _interval ) ;
this . convertToImg ( ) ;
} ,
_render : function ( ) { }
} ) ; // End RibbonBrush
/ * *
* ShadedBrush
* Based on code by Mr . Doob .
* /
fabric . ShadedBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : . 3 ,
width : 1 ,
shadeDistance : 1000 ,
_points : [ ] ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
this . shadeDistance = opt . shadeDistance || 1000 ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points = [ pointer ] ;
var ctx = this . canvas . contextTop ,
color = fabric . util . colorValues ( this . color ) ;
ctx . strokeStyle = 'rgba(' + color [ 0 ] + ',' + color [ 1 ] + ',' + color [ 2 ] + ',' + this . opacity + ')' ;
ctx . lineWidth = this . width ;
ctx . lineJoin = ctx . lineCap = 'round' ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points . push ( pointer ) ;
var ctx = this . canvas . contextTop ,
points = this . _points ;
ctx . beginPath ( ) ;
ctx . moveTo ( points [ points . length - 2 ] . x , points [ points . length - 2 ] . y ) ;
ctx . lineTo ( points [ points . length - 1 ] . x , points [ points . length - 1 ] . y ) ;
ctx . stroke ( ) ;
for ( var i = 0 , len = points . length ; i < len ; i ++ ) {
dx = points [ i ] . x - points [ points . length - 1 ] . x ;
dy = points [ i ] . y - points [ points . length - 1 ] . y ;
d = dx * dx + dy * dy ;
if ( d < this . shadeDistance ) {
ctx . beginPath ( ) ;
ctx . moveTo ( points [ points . length - 1 ] . x + ( dx * 0.2 ) , points [ points . length - 1 ] . y + ( dy * 0.2 ) ) ;
ctx . lineTo ( points [ i ] . x - ( dx * 0.2 ) , points [ i ] . y - ( dy * 0.2 ) ) ;
ctx . stroke ( ) ;
}
}
} ,
onMouseUp : function ( pointer ) {
if ( this . _points . length > 1 ) {
this . convertToImg ( ) ;
}
} ,
_render : function ( ) { }
} ) ; // End ShadedBrush
/ * *
* SketchyBrush
* Based on code by Mr . Doob .
* /
fabric . SketchyBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 1 ,
_count : 0 ,
_points : [ ] ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || this . opacity ;
} ,
onMouseDown : function ( pointer ) {
this . _count = 0 ;
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points = [ pointer ] ;
var ctx = this . canvas . contextTop ,
color = fabric . util . colorValues ( this . color ) ;
//ctx.globalCompositeOperation = 'source-over';
ctx . strokeStyle = 'rgba(' + color [ 0 ] + ',' + color [ 1 ] + ',' + color [ 2 ] + ',' + ( 0.05 * this . opacity ) + ')' ;
ctx . lineWidth = this . width ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points . push ( pointer ) ;
var i , dx , dy , d , factor = . 3 * this . width ,
ctx = this . canvas . contextTop ,
points = this . _points ,
count = this . _count ,
lastPoint = points [ points . length - 2 ] ;
ctx . beginPath ( ) ;
ctx . moveTo ( lastPoint . x , lastPoint . y ) ;
ctx . lineTo ( pointer . x , pointer . y ) ;
ctx . stroke ( ) ;
for ( i = 0 ; i < points . length ; i ++ ) {
dx = points [ i ] . x - points [ count ] . x ;
dy = points [ i ] . y - points [ count ] . y ;
d = dx * dx + dy * dy ;
if ( d < 4000 && Math . random ( ) > d / 2000 ) {
ctx . beginPath ( ) ;
ctx . moveTo ( points [ count ] . x + ( dx * factor ) , points [ count ] . y + ( dy * factor ) ) ;
ctx . lineTo ( points [ i ] . x - ( dx * factor ) , points [ i ] . y - ( dy * factor ) ) ;
ctx . stroke ( ) ;
}
}
this . _count ++ ;
} ,
onMouseUp : function ( pointer ) {
if ( this . _count > 0 ) {
this . convertToImg ( ) ;
}
} ,
_render : function ( ) { }
} ) ; // End SketchyBrush
/ * *
* SpraypaintBrush
* Based on code by Tennison Chan .
* /
fabric . SpraypaintBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 30 ,
_baseWidth : 40 ,
_inkAmount : 0 ,
_interval : 20 ,
_lastPoint : null ,
_point : null ,
brush : null ,
sprayBrushDataUrl : ' data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAT0AAAE / CAMAAAADjeSkAAAyGmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4zLWMwMTEgNjYuMTQ1NjYxLCAyMDEyLzAyLzA2LTE0OjU2OjI3ICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICAgICAgICA8eG1wOkNyZWF0b3JUb29sPkFkb2JlIEZpcmV3b3JrcyBDUzYgKE1hY2ludG9zaCk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMjEtMDUtMjdUMTQ6NTg6NTVaPC94bXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMjEtMDUtMjdUMTQ6NTk6MDJaPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24 + CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI + CiAgICAgICAgIDxkYzpmb3JtYXQ + aW1hZ2UvcG5nPC9kYzpmb3JtYXQ + CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY + CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg
initialize : function ( canvas , opt ) {
var self = this ;
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . opacity = opt . opacity || this . opacity ;
this . color = opt . color || this . color ;
this . canvas . contextTop . lineJoin = 'round' ;
this . canvas . contextTop . lineCap = 'round' ;
this . _reset ( ) ;
fabric . Image . fromURL ( this . sprayBrushDataUrl , function ( brush ) {
self . brush = brush ;
self . brush . filters = [ ] ;
self . _setColor ( self . color || this . color ) ;
} , { crossOrigin : 'anonymous' } ) ;
} ,
_setColor : function ( color ) {
this . color = color ;
this . brush . filters [ 0 ] = new fabric . Image . filters . BlendColor ( { color : color , alpha : 1 , mode : 'tint' } ) ;
this . brush . applyFilters ( ) ;
} ,
onMouseDown : function ( pointer ) {
this . canvas . contextTop . globalAlpha = this . opacity ;
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _point = new fabric . Point ( pointer . x , pointer . y ) ;
this . _lastPoint = this . _point ;
// this.size = this.width + this._baseWidth;
this . size = this . width + this . width / 2 ;
this . _inkAmount = 0 ;
this . _setColor ( this . color ) ;
this . _render ( ) ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = this . _point ;
this . _point = new fabric . Point ( pointer . x , pointer . y ) ;
} ,
onMouseUp : function ( ) {
var self = this ;
setTimeout ( function ( ) {
self . convertToImg ( ) ;
self . _reset ( ) ;
} , this . _interval ) ;
} ,
_render : function ( ) {
var self = this ;
function draw ( ) {
var point , distance , angle , amount , x , y ;
point = new fabric . Point ( self . _point . x || 0 , self . _point . y || 0 ) ;
distance = point . distanceFrom ( self . _lastPoint ) ;
angle = point . angleBetween ( self . _lastPoint ) ;
amount = ( 100 / self . size ) / ( Math . pow ( distance , 2 ) + 1 ) ;
self . _inkAmount += amount ;
self . _inkAmount = Math . max ( self . _inkAmount - distance / 10 , 0 ) ;
x = self . _lastPoint . x + Math . sin ( angle ) - self . size / 2 ;
y = self . _lastPoint . y + Math . cos ( angle ) - self . size / 2 ;
self . canvas . contextTop . drawImage ( self . brush . _element , x , y , self . size , self . size ) ;
if ( self . canvas . _isCurrentlyDrawing ) {
setTimeout ( draw , self . _interval ) ;
} else {
self . _reset ( ) ;
}
}
draw ( ) ;
} ,
_reset : function ( ) {
this . _point = null ;
this . _lastPoint = null ;
this . canvas . contextTop . globalAlpha = 1 ;
}
} ) ; // End SpraypaintBrush
/ * *
* SquaresBrush
* Based on code by Mr . Doob .
* /
fabric . SquaresBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
bgColor : '#fff' ,
opacity : 1 ,
width : 1 ,
_lastPoint : null ,
_drawn : false ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . bgColor = opt . bgColor || '#fff' ;
this . opacity = opt . opacity || this . opacity ;
} ,
onMouseDown : function ( pointer ) {
var ctx = this . canvas . contextTop ,
color = fabric . util . colorValues ( this . color ) ,
bgColor = fabric . util . colorValues ( this . bgColor ) ;
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _lastPoint = pointer ;
this . _drawn = false ;
//ctx.globalCompositeOperation = 'source-over';
this . canvas . contextTop . globalAlpha = this . opacity ;
ctx . fillStyle = 'rgba(' + bgColor [ 0 ] + ',' + bgColor [ 1 ] + ',' + bgColor [ 2 ] + ',' + bgColor [ 3 ] + ')' ;
ctx . strokeStyle = 'rgba(' + color [ 0 ] + ',' + color [ 1 ] + ',' + color [ 2 ] + ',' + color [ 3 ] + ')' ;
ctx . lineWidth = this . width ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
var ctx = this . canvas . contextTop ,
dx = pointer . x - this . _lastPoint . x ,
dy = pointer . y - this . _lastPoint . y ,
angle = 1.57079633 ,
px = Math . cos ( angle ) * dx - Math . sin ( angle ) * dy ,
py = Math . sin ( angle ) * dx + Math . cos ( angle ) * dy ;
ctx . beginPath ( ) ;
ctx . moveTo ( this . _lastPoint . x - px , this . _lastPoint . y - py ) ;
ctx . lineTo ( this . _lastPoint . x + px , this . _lastPoint . y + py ) ;
ctx . lineTo ( pointer . x + px , pointer . y + py ) ;
ctx . lineTo ( pointer . x - px , pointer . y - py ) ;
ctx . lineTo ( this . _lastPoint . x - px , this . _lastPoint . y - py ) ;
ctx . fill ( ) ;
ctx . stroke ( ) ;
this . _lastPoint = pointer ;
this . _drawn = true ;
} ,
onMouseUp : function ( pointer ) {
if ( this . _drawn ) {
this . convertToImg ( ) ;
}
this . canvas . contextTop . globalAlpha = 1 ;
} ,
_render : function ( ) { }
} ) ; // End SquaresBrush
/ * *
* WebBrush
* Based on code by Mr . Doob .
* /
fabric . WebBrush = fabric . util . createClass ( fabric . BaseBrush , {
color : '#000' ,
opacity : 1 ,
width : 1 ,
_count : 0 ,
_points : [ ] ,
initialize : function ( canvas , opt ) {
opt = opt || { } ;
this . canvas = canvas ;
this . width = opt . width || this . width ;
this . color = opt . color || this . color ;
this . opacity = opt . opacity || 1 ;
} ,
onMouseDown : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points = [ pointer ] ;
this . _count = 0 ;
this . _colorValues = fabric . util . colorValues ( this . color ) ;
} ,
onMouseMove : function ( pointer ) {
2024-11-22 09:20:25 +08:00
pointer . x = ( pointer . x * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 4 ] ;
pointer . y = ( pointer . y * this . canvas . getZoom ( ) ) + this . canvas . viewportTransform [ 5 ] ;
2024-03-15 09:21:17 +08:00
this . _points . push ( pointer ) ;
var ctx = this . canvas . contextTop ,
points = this . _points ,
lastPoint = points [ points . length - 2 ] ,
colorValues = this . _colorValues ,
i , dx , dy , d ;
ctx . lineWidth = this . width ;
ctx . strokeStyle = 'rgba(' + colorValues [ 0 ] + ',' + colorValues [ 1 ] + ',' + colorValues [ 2 ] + ',' + ( . 5 * this . opacity ) + ')' ;
ctx . beginPath ( ) ;
ctx . moveTo ( lastPoint . x , lastPoint . y ) ;
ctx . lineTo ( pointer . x , pointer . y ) ;
ctx . stroke ( ) ;
ctx . strokeStyle = 'rgba(' + colorValues [ 0 ] + ',' + colorValues [ 1 ] + ',' + colorValues [ 2 ] + ',' + ( . 1 * this . opacity ) + ')' ;
for ( i = 0 ; i < points . length ; i ++ ) {
dx = points [ i ] . x - points [ this . _count ] . x ;
dy = points [ i ] . y - points [ this . _count ] . y ;
d = dx * dx + dy * dy ;
if ( d < 2500 && Math . random ( ) > . 9 ) {
ctx . beginPath ( ) ;
ctx . moveTo ( points [ this . _count ] . x , points [ this . _count ] . y ) ;
ctx . lineTo ( points [ i ] . x , points [ i ] . y ) ;
ctx . stroke ( ) ;
}
}
this . _count ++ ;
} ,
onMouseUp : function ( pointer ) {
if ( this . _count > 0 ) {
this . convertToImg ( ) ;
}
} ,
_render : function ( ) { }
} ) ; // End WebBrush
} ) ( typeof fabric !== 'undefined' ? fabric : require ( 'fabric' ) . fabric ) ;