fabric 4.5.1-browser → 5.0.0-browser

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/CONTRIBUTING.md +14 -0
  3. package/HEADER.js +1 -1
  4. package/README.md +3 -6
  5. package/SECURITY.md +5 -0
  6. package/build.js +1 -0
  7. package/dist/fabric.js +1160 -668
  8. package/dist/fabric.min.js +1 -1
  9. package/lib/event.js +7 -3
  10. package/package.json +9 -3
  11. package/publish-next.js +15 -0
  12. package/publish.js +3 -0
  13. package/src/brushes/base_brush.class.js +3 -5
  14. package/src/brushes/pattern_brush.class.js +7 -5
  15. package/src/brushes/pencil_brush.class.js +49 -37
  16. package/src/canvas.class.js +27 -57
  17. package/src/filters/saturate_filter.class.js +9 -1
  18. package/src/filters/vibrance_filter.class.js +122 -0
  19. package/src/mixins/animation.mixin.js +20 -25
  20. package/src/mixins/canvas_events.mixin.js +30 -59
  21. package/src/mixins/canvas_grouping.mixin.js +4 -4
  22. package/src/mixins/collection.mixin.js +11 -2
  23. package/src/mixins/eraser_brush.mixin.js +495 -452
  24. package/src/mixins/itext_behavior.mixin.js +7 -1
  25. package/src/mixins/itext_key_behavior.mixin.js +7 -1
  26. package/src/mixins/object_geometry.mixin.js +5 -35
  27. package/src/mixins/object_interactivity.mixin.js +18 -7
  28. package/src/mixins/object_straightening.mixin.js +4 -9
  29. package/src/mixins/observable.mixin.js +22 -0
  30. package/src/parser.js +13 -9
  31. package/src/shapes/circle.class.js +22 -19
  32. package/src/shapes/ellipse.class.js +2 -2
  33. package/src/shapes/group.class.js +24 -32
  34. package/src/shapes/image.class.js +3 -25
  35. package/src/shapes/itext.class.js +10 -0
  36. package/src/shapes/line.class.js +5 -21
  37. package/src/shapes/object.class.js +67 -32
  38. package/src/shapes/path.class.js +17 -18
  39. package/src/shapes/polygon.class.js +11 -10
  40. package/src/shapes/polyline.class.js +33 -24
  41. package/src/shapes/rect.class.js +0 -18
  42. package/src/shapes/text.class.js +120 -58
  43. package/src/shapes/triangle.class.js +0 -15
  44. package/src/static_canvas.class.js +43 -20
  45. package/src/util/animate.js +149 -16
  46. package/src/util/animate_color.js +2 -1
  47. package/src/util/lang_object.js +5 -1
  48. package/src/util/misc.js +193 -42
  49. package/src/util/path.js +89 -52
package/lib/event.js CHANGED
@@ -1368,7 +1368,11 @@ root.gesture = function(conf) {
1368
1368
  var dx = touch.move.x - self.x;
1369
1369
  var dy = touch.move.y - self.y;
1370
1370
  var distance = Math.sqrt(dx * dx + dy * dy);
1371
- scale += distance / start.distance;
1371
+ // If touch start.distance from centroid is 0, scale should not be updated.
1372
+ // This prevents dividing by 0 in cases where start.distance is oddly 0.
1373
+ if (start.distance !== 0) {
1374
+ scale += distance / start.distance;
1375
+ }
1372
1376
  // Calculate rotation.
1373
1377
  var angle = Math.atan2(dx, dy) / RAD_DEG;
1374
1378
  var rotate = (start.angle - angle + 360) % 360 - 180;
@@ -1765,8 +1769,8 @@ root.tap = function(conf) {
1765
1769
  var identifier = touch.identifier || Infinity;
1766
1770
  var pt = conf.tracker[identifier];
1767
1771
  if (!pt) continue;
1768
- var x = (touch.pageX - bbox.x1);
1769
- var y = (touch.pageY - bbox.y1);
1772
+ var x = (touch.pageX - bbox.x1 - parseInt(window.scrollX));
1773
+ var y = (touch.pageY - bbox.y1 - parseInt(window.scrollY));
1770
1774
  ///
1771
1775
  var dx = x - pt.start.x;
1772
1776
  var dy = y - pt.start.y;
package/package.json CHANGED
@@ -2,12 +2,16 @@
2
2
  "name": "fabric",
3
3
  "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
4
4
  "homepage": "http://fabricjs.com/",
5
- "version": "4.5.1-browser",
5
+ "version": "5.0.0-browser",
6
6
  "author": "Juriy Zaytsev <kangax@gmail.com>",
7
7
  "contributors": [
8
8
  {
9
9
  "name": "Andrea Bogazzi",
10
10
  "email": "andreabogazzi79@gmail.com"
11
+ },
12
+ {
13
+ "name": "Steve Eberhardt",
14
+ "email": "melchiar2@gmail.com"
11
15
  }
12
16
  ],
13
17
  "keywords": [
@@ -40,6 +44,7 @@
40
44
  },
41
45
  "license": "MIT",
42
46
  "scripts": {
47
+ "changelog": "auto-changelog -o change-output.md --unreleased-only",
43
48
  "build": "node build.js modules=ALL requirejs exclude=gestures,accessors,erasing",
44
49
  "build:fast": "node build.js modules=ALL requirejs fast exclude=gestures,accessors,erasing",
45
50
  "build:watch": "onchange 'src/**/**' 'HEADER.js' 'lib/**/**' -- npm run build_export",
@@ -65,17 +70,18 @@
65
70
  },
66
71
  "optionalDependencies": {},
67
72
  "devDependencies": {
73
+ "auto-changelog": "^2.3.0",
68
74
  "chalk": "^2.4.1",
69
75
  "eslint": "4.18.x",
70
76
  "nyc": "^15.1.0",
71
- "onchange": "^3.x.x",
77
+ "onchange": "^7.1.0",
72
78
  "pixelmatch": "^4.0.2",
73
79
  "qunit": "^2.13.0",
74
80
  "testem": "^3.2.0",
75
81
  "uglify-js": "3.3.x"
76
82
  },
77
83
  "engines": {
78
- "node": ">=8.0.0"
84
+ "node": ">=14.0.0"
79
85
  },
80
86
  "main": "./dist/fabric.js",
81
87
  "dependencies": {}
@@ -0,0 +1,15 @@
1
+ var cp = require('child_process');
2
+
3
+ console.log('npm version prerelease --preid=rc');
4
+
5
+ cp.execSync('npm version prerelease --preid=rc');
6
+
7
+ console.log('npm run build');
8
+
9
+ cp.execSync('npm run build');
10
+
11
+ console.log('npm publish --tag next');
12
+
13
+ cp.execSync('npm publish --tag next');
14
+
15
+ console.log('pre release package is published');
package/publish.js CHANGED
@@ -2,6 +2,9 @@ var cp = require('child_process');
2
2
  var path = require('path');
3
3
  var fs = require('fs');
4
4
 
5
+ // useful changelog regexp for atom
6
+ // \(#([0-9]+)\) [#$1](https://github.com/fabricjs/fabric.js/pull/$1)
7
+
5
8
  // eslint-disable-next-line no-undef
6
9
  var pkgPath = path.resolve(__dirname, './package.json');
7
10
  var pkgText = fs.readFileSync(pkgPath); // get original pkg text to restore it later
@@ -68,17 +68,15 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
68
68
  /**
69
69
  * Sets brush styles
70
70
  * @private
71
+ * @param {CanvasRenderingContext2D} ctx
71
72
  */
72
- _setBrushStyles: function() {
73
- var ctx = this.canvas.contextTop;
73
+ _setBrushStyles: function (ctx) {
74
74
  ctx.strokeStyle = this.color;
75
75
  ctx.lineWidth = this.width;
76
76
  ctx.lineCap = this.strokeLineCap;
77
77
  ctx.miterLimit = this.strokeMiterLimit;
78
78
  ctx.lineJoin = this.strokeLineJoin;
79
- if (fabric.StaticCanvas.supports('setLineDash')) {
80
- ctx.setLineDash(this.strokeDashArray || []);
81
- }
79
+ ctx.setLineDash(this.strokeDashArray || []);
82
80
  },
83
81
 
84
82
  /**
@@ -29,17 +29,19 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
29
29
 
30
30
  /**
31
31
  * Creates "pattern" instance property
32
+ * @param {CanvasRenderingContext2D} ctx
32
33
  */
33
- getPattern: function() {
34
- return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat');
34
+ getPattern: function(ctx) {
35
+ return ctx.createPattern(this.source || this.getPatternSrc(), 'repeat');
35
36
  },
36
37
 
37
38
  /**
38
39
  * Sets brush styles
40
+ * @param {CanvasRenderingContext2D} ctx
39
41
  */
40
- _setBrushStyles: function() {
41
- this.callSuper('_setBrushStyles');
42
- this.canvas.contextTop.strokeStyle = this.getPattern();
42
+ _setBrushStyles: function(ctx) {
43
+ this.callSuper('_setBrushStyles', ctx);
44
+ ctx.strokeStyle = this.getPattern(ctx);
43
45
  },
44
46
 
45
47
  /**
@@ -13,6 +13,22 @@
13
13
  */
14
14
  decimate: 0.4,
15
15
 
16
+ /**
17
+ * Draws a straight line between last recorded point to current pointer
18
+ * Used for `shift` functionality
19
+ *
20
+ * @type boolean
21
+ * @default false
22
+ */
23
+ drawStraightLine: false,
24
+
25
+ /**
26
+ * The event modifier key that makes the brush draw a straight line.
27
+ * If `null` or 'none' or any other string that is not a modifier key the feature is disabled.
28
+ * @type {'altKey' | 'shiftKey' | 'ctrlKey' | 'none' | undefined | null}
29
+ */
30
+ straightLineKey: 'shiftKey',
31
+
16
32
  /**
17
33
  * Constructor
18
34
  * @param {fabric.Canvas} canvas
@@ -23,6 +39,10 @@
23
39
  this._points = [];
24
40
  },
25
41
 
42
+ needsFullRender: function () {
43
+ return this.callSuper('needsFullRender') || this._hasStraightLine;
44
+ },
45
+
26
46
  /**
27
47
  * Invoked inside on mouse down and mouse move
28
48
  * @param {Object} pointer
@@ -41,6 +61,7 @@
41
61
  if (!this.canvas._isMainEvent(options.e)) {
42
62
  return;
43
63
  }
64
+ this.drawStraightLine = options.e[this.straightLineKey];
44
65
  this._prepareForDrawing(pointer);
45
66
  // capture coordinates immediately
46
67
  // this allows to draw dots (when movement never occurs)
@@ -56,6 +77,7 @@
56
77
  if (!this.canvas._isMainEvent(options.e)) {
57
78
  return;
58
79
  }
80
+ this.drawStraightLine = options.e[this.straightLineKey];
59
81
  if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {
60
82
  return;
61
83
  }
@@ -88,6 +110,7 @@
88
110
  if (!this.canvas._isMainEvent(options.e)) {
89
111
  return true;
90
112
  }
113
+ this.drawStraightLine = false;
91
114
  this.oldEnd = undefined;
92
115
  this._finalizeAndAddPath();
93
116
  return false;
@@ -114,6 +137,10 @@
114
137
  if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) {
115
138
  return false;
116
139
  }
140
+ if (this.drawStraightLine && this._points.length > 1) {
141
+ this._hasStraightLine = true;
142
+ this._points.pop();
143
+ }
117
144
  this._points.push(point);
118
145
  return true;
119
146
  },
@@ -124,8 +151,9 @@
124
151
  */
125
152
  _reset: function() {
126
153
  this._points = [];
127
- this._setBrushStyles();
154
+ this._setBrushStyles(this.canvas.contextTop);
128
155
  this._setShadow();
156
+ this._hasStraightLine = false;
129
157
  },
130
158
 
131
159
  /**
@@ -140,12 +168,13 @@
140
168
  /**
141
169
  * Draw a smooth path on the topCanvas using quadraticCurveTo
142
170
  * @private
171
+ * @param {CanvasRenderingContext2D} [ctx]
143
172
  */
144
- _render: function() {
145
- var ctx = this.canvas.contextTop, i, len,
173
+ _render: function(ctx) {
174
+ var i, len,
146
175
  p1 = this._points[0],
147
176
  p2 = this._points[1];
148
-
177
+ ctx = ctx || this.canvas.contextTop;
149
178
  this._saveAndTransform(ctx);
150
179
  ctx.beginPath();
151
180
  //if we only have 2 points in the path and they are the same
@@ -179,43 +208,26 @@
179
208
  /**
180
209
  * Converts points to SVG path
181
210
  * @param {Array} points Array of points
182
- * @return {String} SVG path
211
+ * @return {(string|number)[][]} SVG path commands
183
212
  */
184
- convertPointsToSVGPath: function(points) {
185
- var path = [], i, width = this.width / 1000,
186
- p1 = new fabric.Point(points[0].x, points[0].y),
187
- p2 = new fabric.Point(points[1].x, points[1].y),
188
- len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;
213
+ convertPointsToSVGPath: function (points) {
214
+ var correction = this.width / 1000;
215
+ return fabric.util.getSmoothPathFromPoints(points, correction);
216
+ },
189
217
 
190
- if (manyPoints) {
191
- multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;
192
- multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;
193
- }
194
- path.push('M ', p1.x - multSignX * width, ' ', p1.y - multSignY * width, ' ');
195
- for (i = 1; i < len; i++) {
196
- if (!p1.eq(p2)) {
197
- var midPoint = p1.midPointFrom(p2);
198
- // p1 is our bezier control point
199
- // midpoint is our endpoint
200
- // start point is p(i-1) value.
201
- path.push('Q ', p1.x, ' ', p1.y, ' ', midPoint.x, ' ', midPoint.y, ' ');
202
- }
203
- p1 = points[i];
204
- if ((i + 1) < points.length) {
205
- p2 = points[i + 1];
206
- }
207
- }
208
- if (manyPoints) {
209
- multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;
210
- multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;
211
- }
212
- path.push('L ', p1.x + multSignX * width, ' ', p1.y + multSignY * width);
213
- return path;
218
+ /**
219
+ * @private
220
+ * @param {(string|number)[][]} pathData SVG path commands
221
+ * @returns {boolean}
222
+ */
223
+ _isEmptySVGPath: function (pathData) {
224
+ var pathString = fabric.util.joinPath(pathData);
225
+ return pathString === 'M 0 0 Q 0 0 0 0 L 0 0';
214
226
  },
215
227
 
216
228
  /**
217
229
  * Creates fabric.Path object to add on canvas
218
- * @param {String} pathData Path data
230
+ * @param {(string|number)[][]} pathData Path data
219
231
  * @return {fabric.Path} Path to add on canvas
220
232
  */
221
233
  createPath: function(pathData) {
@@ -272,8 +284,8 @@
272
284
  if (this.decimate) {
273
285
  this._points = this.decimatePoints(this._points, this.decimate);
274
286
  }
275
- var pathData = this.convertPointsToSVGPath(this._points).join('');
276
- if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') {
287
+ var pathData = this.convertPointsToSVGPath(this._points);
288
+ if (this._isEmptySVGPath(pathData)) {
277
289
  // do not create 0 width/height paths, as they are
278
290
  // rendered inconsistently across browsers
279
291
  // Firefox 4, for example, renders a dot,
@@ -2,10 +2,7 @@
2
2
 
3
3
  var getPointer = fabric.util.getPointer,
4
4
  degreesToRadians = fabric.util.degreesToRadians,
5
- abs = Math.abs,
6
- supportLineDash = fabric.StaticCanvas.supports('setLineDash'),
7
- isTouchEvent = fabric.util.isTouchEvent,
8
- STROKE_OFFSET = 0.5;
5
+ isTouchEvent = fabric.util.isTouchEvent;
9
6
 
10
7
  /**
11
8
  * Canvas class
@@ -40,15 +37,11 @@
40
37
  * @fires dragover
41
38
  * @fires dragenter
42
39
  * @fires dragleave
40
+ * @fires drop:before before drop event. same native event. This is added to handle edge cases
43
41
  * @fires drop
44
42
  * @fires after:render at the end of the render process, receives the context in the callback
45
43
  * @fires before:render at start the render process, receives the context in the callback
46
44
  *
47
- * the following events are deprecated:
48
- * @fires object:rotated at the end of a rotation transform
49
- * @fires object:scaled at the end of a scale transform
50
- * @fires object:moved at the end of translation transform
51
- * @fires object:skewed at the end of a skew transform
52
45
  */
53
46
  fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {
54
47
 
@@ -233,13 +226,6 @@
233
226
  */
234
227
  freeDrawingCursor: 'crosshair',
235
228
 
236
- /**
237
- * Cursor value used for rotation point
238
- * @type String
239
- * @default
240
- */
241
- rotationCursor: 'crosshair',
242
-
243
229
  /**
244
230
  * Cursor value used for disabled elements ( corners with disabled action )
245
231
  * @type String
@@ -345,6 +331,13 @@
345
331
  */
346
332
  targets: [],
347
333
 
334
+ /**
335
+ * When the option is enabled, PointerEvent is used instead of MouseEvent.
336
+ * @type Boolean
337
+ * @default
338
+ */
339
+ enablePointerEvents: false,
340
+
348
341
  /**
349
342
  * Keep track of the hovered target
350
343
  * @type fabric.Object
@@ -420,6 +413,7 @@
420
413
  }
421
414
  if (this.hasLostContext) {
422
415
  this.renderTopLayer(this.contextTop);
416
+ this.hasLostContext = false;
423
417
  }
424
418
  var canvasToDrawOn = this.contextContainer;
425
419
  this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());
@@ -689,21 +683,20 @@
689
683
  * @param {CanvasRenderingContext2D} ctx to draw the selection on
690
684
  */
691
685
  _drawSelection: function (ctx) {
692
- var groupSelector = this._groupSelector,
693
- left = groupSelector.left,
694
- top = groupSelector.top,
695
- aleft = abs(left),
696
- atop = abs(top);
686
+ var selector = this._groupSelector,
687
+ viewportStart = new fabric.Point(selector.ex, selector.ey),
688
+ start = fabric.util.transformPoint(viewportStart, this.viewportTransform),
689
+ viewportExtent = new fabric.Point(selector.ex + selector.left, selector.ey + selector.top),
690
+ extent = fabric.util.transformPoint(viewportExtent, this.viewportTransform),
691
+ minX = Math.min(start.x, extent.x),
692
+ minY = Math.min(start.y, extent.y),
693
+ maxX = Math.max(start.x, extent.x),
694
+ maxY = Math.max(start.y, extent.y),
695
+ strokeOffset = this.selectionLineWidth / 2;
697
696
 
698
697
  if (this.selectionColor) {
699
698
  ctx.fillStyle = this.selectionColor;
700
-
701
- ctx.fillRect(
702
- groupSelector.ex - ((left > 0) ? 0 : -left),
703
- groupSelector.ey - ((top > 0) ? 0 : -top),
704
- aleft,
705
- atop
706
- );
699
+ ctx.fillRect(minX, minY, maxX - minX, maxY - minY);
707
700
  }
708
701
 
709
702
  if (!this.selectionLineWidth || !this.selectionBorderColor) {
@@ -712,31 +705,13 @@
712
705
  ctx.lineWidth = this.selectionLineWidth;
713
706
  ctx.strokeStyle = this.selectionBorderColor;
714
707
 
708
+ minX += strokeOffset;
709
+ minY += strokeOffset;
710
+ maxX -= strokeOffset;
711
+ maxY -= strokeOffset;
715
712
  // selection border
716
- if (this.selectionDashArray.length > 1 && !supportLineDash) {
717
-
718
- var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
719
- py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop);
720
-
721
- ctx.beginPath();
722
-
723
- fabric.util.drawDashedLine(ctx, px, py, px + aleft, py, this.selectionDashArray);
724
- fabric.util.drawDashedLine(ctx, px, py + atop - 1, px + aleft, py + atop - 1, this.selectionDashArray);
725
- fabric.util.drawDashedLine(ctx, px, py, px, py + atop, this.selectionDashArray);
726
- fabric.util.drawDashedLine(ctx, px + aleft - 1, py, px + aleft - 1, py + atop, this.selectionDashArray);
727
-
728
- ctx.closePath();
729
- ctx.stroke();
730
- }
731
- else {
732
- fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);
733
- ctx.strokeRect(
734
- groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft),
735
- groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop),
736
- aleft,
737
- atop
738
- );
739
- }
713
+ fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);
714
+ ctx.strokeRect(minX, minY, maxX - minX, maxY - minY);
740
715
  },
741
716
 
742
717
  /**
@@ -1108,17 +1083,12 @@
1108
1083
  e: e,
1109
1084
  selected: added,
1110
1085
  deselected: removed,
1111
- // added for backward compatibility
1112
- // deprecated
1113
- updated: added[0] || removed[0],
1114
- target: this._activeObject,
1115
1086
  });
1116
1087
  }
1117
1088
  else if (objects.length > 0) {
1118
1089
  this.fire('selection:created', {
1119
1090
  e: e,
1120
1091
  selected: added,
1121
- target: this._activeObject,
1122
1092
  });
1123
1093
  }
1124
1094
  else if (oldObjects.length > 0) {
@@ -15,7 +15,7 @@
15
15
  * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
16
16
  * @example
17
17
  * var filter = new fabric.Image.filters.Saturation({
18
- * saturation: 100
18
+ * saturation: 1
19
19
  * });
20
20
  * object.filters.push(filter);
21
21
  * object.applyFilters();
@@ -43,6 +43,14 @@
43
43
  'gl_FragColor = color;\n' +
44
44
  '}',
45
45
 
46
+ /**
47
+ * Saturation value, from -1 to 1.
48
+ * Increases/decreases the color saturation.
49
+ * A value of 0 has no effect.
50
+ *
51
+ * @param {Number} saturation
52
+ * @default
53
+ */
46
54
  saturation: 0,
47
55
 
48
56
  mainParameter: 'saturation',
@@ -0,0 +1,122 @@
1
+ (function(global) {
2
+
3
+ 'use strict';
4
+
5
+ var fabric = global.fabric || (global.fabric = { }),
6
+ filters = fabric.Image.filters,
7
+ createClass = fabric.util.createClass;
8
+
9
+ /**
10
+ * Vibrance filter class
11
+ * @class fabric.Image.filters.Vibrance
12
+ * @memberOf fabric.Image.filters
13
+ * @extends fabric.Image.filters.BaseFilter
14
+ * @see {@link fabric.Image.filters.Vibrance#initialize} for constructor definition
15
+ * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}
16
+ * @example
17
+ * var filter = new fabric.Image.filters.Vibrance({
18
+ * vibrance: 1
19
+ * });
20
+ * object.filters.push(filter);
21
+ * object.applyFilters();
22
+ */
23
+ filters.Vibrance = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Vibrance.prototype */ {
24
+
25
+ /**
26
+ * Filter type
27
+ * @param {String} type
28
+ * @default
29
+ */
30
+ type: 'Vibrance',
31
+
32
+ fragmentSource: 'precision highp float;\n' +
33
+ 'uniform sampler2D uTexture;\n' +
34
+ 'uniform float uVibrance;\n' +
35
+ 'varying vec2 vTexCoord;\n' +
36
+ 'void main() {\n' +
37
+ 'vec4 color = texture2D(uTexture, vTexCoord);\n' +
38
+ 'float max = max(color.r, max(color.g, color.b));\n' +
39
+ 'float avg = (color.r + color.g + color.b) / 3.0;\n' +
40
+ 'float amt = (abs(max - avg) * 2.0) * uVibrance;\n' +
41
+ 'color.r += max != color.r ? (max - color.r) * amt : 0.00;\n' +
42
+ 'color.g += max != color.g ? (max - color.g) * amt : 0.00;\n' +
43
+ 'color.b += max != color.b ? (max - color.b) * amt : 0.00;\n' +
44
+ 'gl_FragColor = color;\n' +
45
+ '}',
46
+
47
+ /**
48
+ * Vibrance value, from -1 to 1.
49
+ * Increases/decreases the saturation of more muted colors with less effect on saturated colors.
50
+ * A value of 0 has no effect.
51
+ *
52
+ * @param {Number} vibrance
53
+ * @default
54
+ */
55
+ vibrance: 0,
56
+
57
+ mainParameter: 'vibrance',
58
+
59
+ /**
60
+ * Constructor
61
+ * @memberOf fabric.Image.filters.Vibrance.prototype
62
+ * @param {Object} [options] Options object
63
+ * @param {Number} [options.vibrance=0] Vibrance value for the image (between -1 and 1)
64
+ */
65
+
66
+ /**
67
+ * Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.
68
+ *
69
+ * @param {Object} options
70
+ * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.
71
+ */
72
+ applyTo2d: function(options) {
73
+ if (this.vibrance === 0) {
74
+ return;
75
+ }
76
+ var imageData = options.imageData,
77
+ data = imageData.data, len = data.length,
78
+ adjust = -this.vibrance, i, max, avg, amt;
79
+
80
+ for (i = 0; i < len; i += 4) {
81
+ max = Math.max(data[i], data[i + 1], data[i + 2]);
82
+ avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
83
+ amt = ((Math.abs(max - avg) * 2 / 255) * adjust);
84
+ data[i] += max !== data[i] ? (max - data[i]) * amt : 0;
85
+ data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * amt : 0;
86
+ data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * amt : 0;
87
+ }
88
+ },
89
+
90
+ /**
91
+ * Return WebGL uniform locations for this filter's shader.
92
+ *
93
+ * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.
94
+ * @param {WebGLShaderProgram} program This filter's compiled shader program.
95
+ */
96
+ getUniformLocations: function(gl, program) {
97
+ return {
98
+ uVibrance: gl.getUniformLocation(program, 'uVibrance'),
99
+ };
100
+ },
101
+
102
+ /**
103
+ * Send data from this filter to its shader program's uniforms.
104
+ *
105
+ * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.
106
+ * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects
107
+ */
108
+ sendUniformData: function(gl, uniformLocations) {
109
+ gl.uniform1f(uniformLocations.uVibrance, -this.vibrance);
110
+ },
111
+ });
112
+
113
+ /**
114
+ * Returns filter instance from an object representation
115
+ * @static
116
+ * @param {Object} object Object to create an instance from
117
+ * @param {Function} [callback] to be invoked after filter creation
118
+ * @return {fabric.Image.filters.Vibrance} Instance of fabric.Image.filters.Vibrance
119
+ */
120
+ fabric.Image.filters.Vibrance.fromObject = fabric.Image.filters.BaseFilter.fromObject;
121
+
122
+ })(typeof exports !== 'undefined' ? exports : this);