This is an automated email from the ASF dual-hosted git repository.
solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push:
new c8de750 [OPENMEETINGS-2151] fabric.js is updated
c8de750 is described below
commit c8de7505010553f780a4885f4ee6d599b14908c3
Author: Maxim Solodovnik <[email protected]>
AuthorDate: Fri Jan 10 16:19:52 2020 +0700
[OPENMEETINGS-2151] fabric.js is updated
---
.../org/apache/openmeetings/web/room/wb/fabric.js | 831 +++++++++++++++------
.../apache/openmeetings/web/room/wb/raw-player.js | 34 +-
2 files changed, 614 insertions(+), 251 deletions(-)
diff --git
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
index 509f38c..fcf17b0 100644
---
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
+++
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/fabric.js
@@ -2,7 +2,7 @@
/* build: `node build.js modules=ALL exclude=gestures,accessors requirejs
minifier=uglifyjs` */
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
-var fabric = fabric || { version: '3.3.0' };
+var fabric = fabric || { version: '3.6.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
@@ -75,8 +75,11 @@ fabric.SHARED_ATTRIBUTES = [
*/
fabric.DPI = 96;
fabric.reNum = '(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:[eE][-+]?\\d+)?)';
+fabric.rePathCommand =
/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:[eE][-+]?\d+)?)/ig;
+fabric.reNonWord = /[ \n\.,;!\?\-]/;
fabric.fontPaths = { };
fabric.iMatrix = [1, 0, 0, 1, 0, 0];
+fabric.svgNS = 'http://www.w3.org/2000/svg';
/**
* Pixel limit for cache canvases. 1Mpx , 4Mpx should be fine.
@@ -620,7 +623,6 @@ fabric.CommonMethods = {
var sqrt = Math.sqrt,
atan2 = Math.atan2,
pow = Math.pow,
- abs = Math.abs,
PiBy180 = Math.PI / 180,
PiBy2 = Math.PI / 2;
@@ -782,9 +784,15 @@ fabric.CommonMethods = {
/**
* Returns coordinates of points's bounding rectangle (left, top, width,
height)
* @param {Array} points 4 points array
+ * @param {Array} [transform] an array of 6 numbers representing a 2x3
transform matrix
* @return {Object} Object with left, top, width, height properties
*/
- makeBoundingBoxFromPoints: function(points) {
+ makeBoundingBoxFromPoints: function(points, transform) {
+ if (transform) {
+ for (var i = 0; i < points.length; i++) {
+ points[i] = fabric.util.transformPoint(points[i], transform);
+ }
+ }
var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x],
minX = fabric.util.array.min(xPoints),
maxX = fabric.util.array.max(xPoints),
@@ -1275,7 +1283,7 @@ fabric.CommonMethods = {
},
/**
- * Decomposes standard 2x2 matrix into transform componentes
+ * Decomposes standard 2x3 matrix into transform components
* @static
* @memberOf fabric.util
* @param {Array} a transformMatrix
@@ -1298,10 +1306,113 @@ fabric.CommonMethods = {
};
},
+ /**
+ * Returns a transform matrix starting from an object of the same kind of
+ * the one returned from qrDecompose, useful also if you want to calculate
some
+ * transformations from an object that is not enlived yet
+ * @static
+ * @memberOf fabric.util
+ * @param {Object} options
+ * @param {Number} [options.angle] angle in degrees
+ * @return {Number[]} transform matrix
+ */
+ calcRotateMatrix: function(options) {
+ if (!options.angle) {
+ return fabric.iMatrix.concat();
+ }
+ var theta = fabric.util.degreesToRadians(options.angle),
+ cos = fabric.util.cos(theta),
+ sin = fabric.util.sin(theta);
+ return [cos, sin, -sin, cos, 0, 0];
+ },
+
+ /**
+ * Returns a transform matrix starting from an object of the same kind of
+ * the one returned from qrDecompose, useful also if you want to calculate
some
+ * transformations from an object that is not enlived yet.
+ * is called DimensionsTransformMatrix because those properties are the
one that influence
+ * the size of the resulting box of the object.
+ * @static
+ * @memberOf fabric.util
+ * @param {Object} options
+ * @param {Number} [options.scaleX]
+ * @param {Number} [options.scaleY]
+ * @param {Boolean} [options.flipX]
+ * @param {Boolean} [options.flipY]
+ * @param {Number} [options.skewX]
+ * @param {Number} [options.skewX]
+ * @return {Number[]} transform matrix
+ */
+ calcDimensionsMatrix: function(options) {
+ var scaleX = typeof options.scaleX === 'undefined' ? 1 : options.scaleX,
+ scaleY = typeof options.scaleY === 'undefined' ? 1 : options.scaleY,
+ scaleMatrix = [
+ options.flipX ? -scaleX : scaleX,
+ 0,
+ 0,
+ options.flipY ? -scaleY : scaleY,
+ 0,
+ 0],
+ multiply = fabric.util.multiplyTransformMatrices,
+ degreesToRadians = fabric.util.degreesToRadians;
+ if (options.skewX) {
+ scaleMatrix = multiply(
+ scaleMatrix,
+ [1, 0, Math.tan(degreesToRadians(options.skewX)), 1],
+ true);
+ }
+ if (options.skewY) {
+ scaleMatrix = multiply(
+ scaleMatrix,
+ [1, Math.tan(degreesToRadians(options.skewY)), 0, 1],
+ true);
+ }
+ return scaleMatrix;
+ },
+
+ /**
+ * Returns a transform matrix starting from an object of the same kind of
+ * the one returned from qrDecompose, useful also if you want to calculate
some
+ * transformations from an object that is not enlived yet
+ * @static
+ * @memberOf fabric.util
+ * @param {Object} options
+ * @param {Number} [options.angle]
+ * @param {Number} [options.scaleX]
+ * @param {Number} [options.scaleY]
+ * @param {Boolean} [options.flipX]
+ * @param {Boolean} [options.flipY]
+ * @param {Number} [options.skewX]
+ * @param {Number} [options.skewX]
+ * @param {Number} [options.translateX]
+ * @param {Number} [options.translateY]
+ * @return {Number[]} transform matrix
+ */
+ composeMatrix: function(options) {
+ var matrix = [1, 0, 0, 1, options.translateX || 0, options.translateY ||
0],
+ multiply = fabric.util.multiplyTransformMatrices;
+ if (options.angle) {
+ matrix = multiply(matrix, fabric.util.calcRotateMatrix(options));
+ }
+ if (options.scaleX || options.scaleY || options.skewX || options.skewY
|| options.flipX || options.flipY) {
+ matrix = multiply(matrix, fabric.util.calcDimensionsMatrix(options));
+ }
+ return matrix;
+ },
+
+ /**
+ * Returns a transform matrix that has the same effect of scaleX, scaleY
and skewX.
+ * Is deprecated for composeMatrix. Please do not use it.
+ * @static
+ * @deprecated since 3.4.0
+ * @memberOf fabric.util
+ * @param {Number} scaleX
+ * @param {Number} scaleY
+ * @param {Number} skewX
+ * @return {Number[]} transform matrix
+ */
customTransformMatrix: function(scaleX, scaleY, skewX) {
- var skewMatrixX = [1, 0, abs(Math.tan(skewX * PiBy180)), 1],
- scaleMatrix = [abs(scaleX), 0, 0, abs(scaleY)];
- return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX,
true);
+ return fabric.util.composeMatrix({ scaleX: scaleX, scaleY: scaleY,
skewX: skewX });
},
/**
@@ -2644,29 +2755,13 @@ fabric.CommonMethods = {
* Wrapper around `console.log` (when available)
* @param {*} [values] Values to log
*/
-fabric.log = function() { };
+fabric.log = console.log;
/**
* Wrapper around `console.warn` (when available)
* @param {*} [values] Values to log as a warning
*/
-fabric.warn = function() { };
-
-/* eslint-disable */
-if (typeof console !== 'undefined') {
-
- ['log', 'warn'].forEach(function(methodName) {
-
- if (typeof console[methodName] !== 'undefined' &&
- typeof console[methodName].apply === 'function') {
-
- fabric[methodName] = function() {
- return console[methodName].apply(console, arguments);
- };
- }
- });
-}
-/* eslint-enable */
+fabric.warn = console.warn;
(function() {
@@ -2675,6 +2770,10 @@ if (typeof console !== 'undefined') {
return false;
}
+ function defaultEasing(t, b, c, d) {
+ return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
+ }
+
/**
* Changes value from one to another within certain period of time, invoking
callbacks as value is being changed.
* @memberOf fabric.util
@@ -2699,7 +2798,7 @@ if (typeof console !== 'undefined') {
onChange = options.onChange || noop,
abort = options.abort || noop,
onComplete = options.onComplete || noop,
- easing = options.easing || function(t, b, c, d) {return -c *
Math.cos(t / d * (Math.PI / 2)) + c + b;},
+ easing = options.easing || defaultEasing,
startValue = 'startValue' in options ? options.startValue : 0,
endValue = 'endValue' in options ? options.endValue : 100,
byValue = options.byValue || endValue - startValue;
@@ -2709,24 +2808,26 @@ if (typeof console !== 'undefined') {
(function tick(ticktime) {
// TODO: move abort call after calculation
// and pass (current,valuePerc, timePerc) as arguments
- if (abort()) {
- onComplete(endValue, 1, 1);
- return;
- }
time = ticktime || +new Date();
var currentTime = time > finish ? duration : (time - start),
timePerc = currentTime / duration,
current = easing(currentTime, startValue, byValue, duration),
valuePerc = Math.abs((current - startValue) / byValue);
- onChange(current, valuePerc, timePerc);
+ if (abort()) {
+ onComplete(endValue, 1, 1);
+ return;
+ }
if (time > finish) {
- options.onComplete && options.onComplete();
+ onChange(endValue, 1, 1);
+ onComplete(endValue, 1, 1);
return;
}
- requestAnimFrame(tick);
+ else {
+ onChange(current, valuePerc, timePerc);
+ requestAnimFrame(tick);
+ }
})(start);
});
-
}
var _requestAnimFrame = fabric.window.requestAnimationFrame ||
@@ -3270,7 +3371,9 @@ if (typeof console !== 'undefined') {
colorAttributes = {
stroke: 'strokeOpacity',
fill: 'fillOpacity'
- };
+ },
+
+ fSize = 'font-size', cPath = 'clip-path';
fabric.svgValidTagNamesRegEx = getSvgRegex(svgValidTagNames);
fabric.svgViewBoxElementsRegEx = getSvgRegex(svgViewBoxElements);
@@ -3685,14 +3788,14 @@ if (typeof console !== 'undefined') {
y = el.getAttribute('y') || 0,
el2 = elementById(doc, xlink).cloneNode(true),
currentTrans = (el2.getAttribute('transform') || '') + ' translate('
+ x + ', ' + y + ')',
- parentNode, oldLength = nodelist.length, attr, j, attrs, len;
+ parentNode, oldLength = nodelist.length, attr, j, attrs, len,
namespace = fabric.svgNS;
applyViewboxTransform(el2);
if (/^svg$/i.test(el2.nodeName)) {
- var el3 = el2.ownerDocument.createElement('g');
+ var el3 = el2.ownerDocument.createElementNS(namespace, 'g');
for (j = 0, attrs = el2.attributes, len = attrs.length; j < len; j++) {
attr = attrs.item(j);
- el3.setAttribute(attr.nodeName, attr.nodeValue);
+ el3.setAttributeNS(namespace, attr.nodeName, attr.nodeValue);
}
// el2.firstChild != null
while (el2.firstChild) {
@@ -3774,12 +3877,14 @@ if (typeof console !== 'undefined') {
parsedDim.height = parseUnit(heightAttr);
return parsedDim;
}
-
minX = -parseFloat(viewBoxAttr[1]);
minY = -parseFloat(viewBoxAttr[2]);
viewBoxWidth = parseFloat(viewBoxAttr[3]);
viewBoxHeight = parseFloat(viewBoxAttr[4]);
-
+ parsedDim.minX = minX;
+ parsedDim.minY = minY;
+ parsedDim.viewBoxWidth = viewBoxWidth;
+ parsedDim.viewBoxHeight = viewBoxHeight;
if (!missingDimAttr) {
parsedDim.width = parseUnit(widthAttr);
parsedDim.height = parseUnit(heightAttr);
@@ -3835,7 +3940,7 @@ if (typeof console !== 'undefined') {
(minY * scaleY + heightDiff) + ') ';
parsedDim.viewboxTransform = fabric.parseTransformAttribute(matrix);
if (element.nodeName === 'svg') {
- el = element.ownerDocument.createElement('g');
+ el = element.ownerDocument.createElementNS(fabric.svgNS, 'g');
// element.firstChild != null
while (element.firstChild) {
el.appendChild(element.firstChild);
@@ -3938,7 +4043,7 @@ if (typeof console !== 'undefined') {
recursivelyParseGradientsXlink(doc, referencedGradient);
}
gradientsAttrs.forEach(function(attr) {
- if (!gradient.hasAttribute(attr)) {
+ if (referencedGradient && !gradient.hasAttribute(attr) &&
referencedGradient.hasAttribute(attr)) {
gradient.setAttribute(attr, referencedGradient.getAttribute(attr));
}
});
@@ -4060,13 +4165,21 @@ if (typeof console !== 'undefined') {
}, { });
// add values parsed from style, which take precedence over attributes
// (see:
http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)
- ownAttributes = extend(ownAttributes,
- extend(getGlobalStylesForElement(element, svgUid),
fabric.parseStyleAttribute(element)));
-
+ var cssAttrs = extend(
+ getGlobalStylesForElement(element, svgUid),
+ fabric.parseStyleAttribute(element)
+ );
+ ownAttributes = extend(
+ ownAttributes,
+ cssAttrs
+ );
+ if (cssAttrs[cPath]) {
+ element.setAttribute(cPath, cssAttrs[cPath]);
+ }
fontSize = parentFontSize = parentAttributes.fontSize ||
fabric.Text.DEFAULT_SVG_FONT_SIZE;
- if (ownAttributes['font-size']) {
+ if (ownAttributes[fSize]) {
// looks like the minimum should be 9px when dealing with ems. this is
what looks like in browsers.
- ownAttributes['font-size'] = fontSize =
parseUnit(ownAttributes['font-size'], parentFontSize);
+ ownAttributes[fSize] = fontSize = parseUnit(ownAttributes[fSize],
parentFontSize);
}
var normalizedAttr, normalizedValue, normalizedStyle = {};
@@ -4282,7 +4395,7 @@ if (typeof console !== 'undefined') {
})(typeof exports !== 'undefined' ? exports : this);
-fabric.ElementsParser = function(elements, callback, options, reviver,
parsingOptions) {
+fabric.ElementsParser = function(elements, callback, options, reviver,
parsingOptions, doc) {
this.elements = elements;
this.callback = callback;
this.options = options;
@@ -4290,6 +4403,7 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
this.svgUid = (options && options.svgUid) || 0;
this.parsingOptions = parsingOptions;
this.regexUrl = /^url\(['"]?#([^'"]+)['"]?\)/g;
+ this.doc = doc;
};
(function(proto) {
@@ -4330,13 +4444,13 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
var _this = this;
return function(obj) {
var _options;
- _this.resolveGradient(obj, 'fill');
- _this.resolveGradient(obj, 'stroke');
+ _this.resolveGradient(obj, el, 'fill');
+ _this.resolveGradient(obj, el, 'stroke');
if (obj instanceof fabric.Image && obj._originalElement) {
_options = obj.parsePreserveAspectRatioAttribute(el);
}
obj._removeTransformMatrix(_options);
- _this.resolveClipPath(obj);
+ _this.resolveClipPath(obj, el);
_this.reviver && _this.reviver(el, obj);
_this.instances[index] = obj;
_this.checkIfDone();
@@ -4344,19 +4458,22 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
};
proto.extractPropertyDefinition = function(obj, property, storage) {
- var value = obj[property];
- if (!(/^url\(/).test(value)) {
+ var value = obj[property], regex = this.regexUrl;
+ if (!regex.test(value)) {
return;
}
- var id = this.regexUrl.exec(value)[1];
- this.regexUrl.lastIndex = 0;
+ regex.lastIndex = 0;
+ var id = regex.exec(value)[1];
+ regex.lastIndex = 0;
return fabric[storage][this.svgUid][id];
};
- proto.resolveGradient = function(obj, property) {
+ proto.resolveGradient = function(obj, el, property) {
var gradientDef = this.extractPropertyDefinition(obj, property,
'gradientDefs');
if (gradientDef) {
- obj.set(property, fabric.Gradient.fromElement(gradientDef, obj));
+ var opacityAttr = el.getAttribute(property + '-opacity');
+ var gradient = fabric.Gradient.fromElement(gradientDef, obj,
opacityAttr, this.options);
+ obj.set(property, gradient);
}
};
@@ -4368,12 +4485,19 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
};
};
- proto.resolveClipPath = function(obj) {
+ proto.resolveClipPath = function(obj, usingElement) {
var clipPath = this.extractPropertyDefinition(obj, 'clipPath',
'clipPaths'),
element, klass, objTransformInv, container, gTransform, options;
if (clipPath) {
container = [];
objTransformInv = fabric.util.invertTransform(obj.calcTransformMatrix());
+ // move the clipPath tag as sibling to the real element that is using it
+ var clipPathTag = clipPath[0].parentNode;
+ var clipPathOwner = usingElement;
+ while (clipPathOwner.parentNode &&
clipPathOwner.getAttribute('clip-path') !== obj.clipPath) {
+ clipPathOwner = clipPathOwner.parentNode;
+ }
+ clipPathOwner.parentNode.appendChild(clipPathTag);
for (var i = 0; i < clipPath.length; i++) {
element = clipPath[i];
klass = this.findTag(element);
@@ -4393,6 +4517,9 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
objTransformInv,
clipPath.calcTransformMatrix()
);
+ if (clipPath.clipPath) {
+ this.resolveClipPath(clipPath, clipPathOwner);
+ }
var options = fabric.util.qrDecompose(gTransform);
clipPath.flipX = false;
clipPath.flipY = false;
@@ -5572,7 +5699,7 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
(function() {
/* _FROM_SVG_START_ */
- function getColorStop(el) {
+ function getColorStop(el, multiplier) {
var style = el.getAttribute('style'),
offset = el.getAttribute('offset') || 0,
color, colorAlpha, opacity, i;
@@ -5612,7 +5739,7 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
color = new fabric.Color(color);
colorAlpha = color.getAlpha();
opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);
- opacity *= colorAlpha;
+ opacity *= colorAlpha * multiplier;
return {
offset: offset,
@@ -5667,17 +5794,67 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
offsetY: 0,
/**
+ * A transform matrix to apply to the gradient before painting.
+ * Imported from svg gradients, is not applied with the current transform
in the center.
+ * Before this transform is applied, the origin point is at the top left
corner of the object
+ * plus the addition of offsetY and offsetX.
+ * @type Number[]
+ * @default null
+ */
+ gradientTransform: null,
+
+ /**
+ * coordinates units for coords.
+ * If `pixels`, the number of coords are in the same unit of width /
height.
+ * If set as `percentage` the coords are still a number, but 1 means 100%
of width
+ * for the X and 100% of the height for the y. It can be bigger than 1 and
negative.
+ * allowed values pixels or percentage.
+ * @type String
+ * @default 'pixels'
+ */
+ gradientUnits: 'pixels',
+
+ /**
+ * Gradient type linear or radial
+ * @type String
+ * @default 'pixels'
+ */
+ type: 'linear',
+
+ /**
* Constructor
- * @param {Object} [options] Options object with type, coords,
gradientUnits and colorStops
+ * @param {Object} options Options object with type, coords, gradientUnits
and colorStops
+ * @param {Object} [options.type] gradient type linear or radial
+ * @param {Object} [options.gradientUnits] gradient units
+ * @param {Object} [options.offsetX] SVG import compatibility
+ * @param {Object} [options.offsetY] SVG import compatibility
+ * @param {Object[]} options.colorStops contains the colorstops.
+ * @param {Object} options.coords contains the coords of the gradient
+ * @param {Number} [options.coords.x1] X coordiante of the first point for
linear or of the focal point for radial
+ * @param {Number} [options.coords.y1] Y coordiante of the first point for
linear or of the focal point for radial
+ * @param {Number} [options.coords.x2] X coordiante of the second point
for linear or of the center point for radial
+ * @param {Number} [options.coords.y2] Y coordiante of the second point
for linear or of the center point for radial
+ * @param {Number} [options.coords.r1] only for radial gradient, radius of
the inner circle
+ * @param {Number} [options.coords.r2] only for radial gradient, radius of
the external circle
* @return {fabric.Gradient} thisArg
*/
initialize: function(options) {
options || (options = { });
+ options.coords || (options.coords = { });
- var coords = { };
+ var coords, _this = this;
- this.id = fabric.Object.__uid++;
- this.type = options.type || 'linear';
+ // sets everything, then coords and colorstops get sets again
+ Object.keys(options).forEach(function(option) {
+ _this[option] = options[option];
+ });
+
+ if (this.id) {
+ this.id += '_' + fabric.Object.__uid++;
+ }
+ else {
+ this.id = fabric.Object.__uid++;
+ }
coords = {
x1: options.coords.x1 || 0,
@@ -5690,13 +5867,9 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
coords.r1 = options.coords.r1 || 0;
coords.r2 = options.coords.r2 || 0;
}
+
this.coords = coords;
this.colorStops = options.colorStops.slice();
- if (options.gradientTransform) {
- this.gradientTransform = options.gradientTransform;
- }
- this.offsetX = options.offsetX || this.offsetX;
- this.offsetY = options.offsetY || this.offsetY;
},
/**
@@ -5728,6 +5901,7 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
colorStops: this.colorStops,
offsetX: this.offsetX,
offsetY: this.offsetY,
+ gradientUnits: this.gradientUnits,
gradientTransform: this.gradientTransform ?
this.gradientTransform.concat() : this.gradientTransform
};
fabric.util.populateWithProperties(this, object, propertiesToInclude);
@@ -5746,23 +5920,33 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
markup, commonAttributes, colorStops = clone(this.colorStops, true),
needsSwap = coords.r1 > coords.r2,
transform = this.gradientTransform ? this.gradientTransform.concat()
: fabric.iMatrix.concat(),
- offsetX = object.width / 2 - this.offsetX, offsetY = object.height /
2 - this.offsetY,
- withViewport = !!options.additionalTransform;
+ offsetX = -this.offsetX, offsetY = -this.offsetY,
+ withViewport = !!options.additionalTransform,
+ gradientUnits = this.gradientUnits === 'pixels' ? 'userSpaceOnUse' :
'objectBoundingBox';
// colorStops must be sorted ascending
colorStops.sort(function(a, b) {
return a.offset - b.offset;
});
+ if (gradientUnits === 'objectBoundingBox') {
+ offsetX /= object.width;
+ offsetY /= object.height;
+ }
+ else {
+ offsetX += object.width / 2;
+ offsetY += object.height / 2;
+ }
if (object.type === 'path') {
offsetX -= object.pathOffset.x;
offsetY -= object.pathOffset.y;
}
+
transform[4] -= offsetX;
transform[5] -= offsetY;
commonAttributes = 'id="SVGID_' + this.id +
- '" gradientUnits="userSpaceOnUse"';
+ '" gradientUnits="' + gradientUnits + '"';
commonAttributes += ' gradientTransform="' + (withViewport ?
options.additionalTransform + ' ' : '') +
fabric.util.matrixToSVG(transform) + '" ';
@@ -5873,11 +6057,18 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
* @memberOf fabric.Gradient
* @param {SVGGradientElement} el SVG gradient element
* @param {fabric.Object} instance
+ * @param {String} opacityAttr A fill-opacity or stroke-opacity attribute
to multiply to each stop's opacity.
+ * @param {Object} svgOptions an object containing the size of the SVG in
order to parse correctly graidents
+ * that uses gradientUnits as 'userSpaceOnUse' and percentages.
+ * @param {Object.number} viewBoxWidth width part of the viewBox attribute
on svg
+ * @param {Object.number} viewBoxHeight height part of the viewBox
attribute on svg
+ * @param {Object.number} width width part of the svg tag if viewBox is
not specified
+ * @param {Object.number} height height part of the svg tag if viewBox is
not specified
* @return {fabric.Gradient} Gradient instance
* @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
* @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
*/
- fromElement: function(el, instance) {
+ fromElement: function(el, instance, opacityAttr, svgOptions) {
/**
* @example:
*
@@ -5911,59 +6102,73 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
*
*/
+ var multiplier = parseFloat(opacityAttr) / (/%$/.test(opacityAttr) ? 100
: 1);
+ multiplier = multiplier < 0 ? 0 : multiplier > 1 ? 1 : multiplier;
+ if (isNaN(multiplier)) {
+ multiplier = 1;
+ }
+
var colorStopEls = el.getElementsByTagName('stop'),
type,
- gradientUnits = el.getAttribute('gradientUnits') ||
'objectBoundingBox',
- gradientTransform = el.getAttribute('gradientTransform'),
+ gradientUnits = el.getAttribute('gradientUnits') ===
'userSpaceOnUse' ?
+ 'pixels' : 'percentage',
+ gradientTransform = el.getAttribute('gradientTransform') || '',
colorStops = [],
- coords, ellipseMatrix, i;
-
+ coords, i, offsetX = 0, offsetY = 0,
+ transformMatrix;
if (el.nodeName === 'linearGradient' || el.nodeName ===
'LINEARGRADIENT') {
type = 'linear';
+ coords = getLinearCoords(el);
}
else {
type = 'radial';
- }
-
- if (type === 'linear') {
- coords = getLinearCoords(el);
- }
- else if (type === 'radial') {
coords = getRadialCoords(el);
}
for (i = colorStopEls.length; i--; ) {
- colorStops.push(getColorStop(colorStopEls[i]));
+ colorStops.push(getColorStop(colorStopEls[i], multiplier));
}
- ellipseMatrix = _convertPercentUnitsToValues(instance, coords,
gradientUnits);
+ transformMatrix = fabric.parseTransformAttribute(gradientTransform);
+
+ __convertPercentUnitsToValues(instance, coords, svgOptions,
gradientUnits);
+
+ if (gradientUnits === 'pixels') {
+ offsetX = -instance.left;
+ offsetY = -instance.top;
+ }
var gradient = new fabric.Gradient({
+ id: el.getAttribute('id'),
type: type,
coords: coords,
colorStops: colorStops,
- offsetX: -instance.left,
- offsetY: -instance.top
+ gradientUnits: gradientUnits,
+ gradientTransform: transformMatrix,
+ offsetX: offsetX,
+ offsetY: offsetY,
});
- if (gradientTransform || ellipseMatrix !== '') {
- gradient.gradientTransform =
fabric.parseTransformAttribute((gradientTransform || '') + ellipseMatrix);
- }
-
return gradient;
},
/* _FROM_SVG_END_ */
/**
* Returns {@link fabric.Gradient} instance from its object representation
+ * this function is uniquely used by Object.setGradient and is deprecated
with it.
* @static
+ * @deprecated since 3.4.0
* @memberOf fabric.Gradient
* @param {Object} obj
* @param {Object} [options] Options object
*/
forObject: function(obj, options) {
options || (options = { });
- _convertPercentUnitsToValues(obj, options.coords, 'userSpaceOnUse');
+ __convertPercentUnitsToValues(obj, options.coords,
options.gradientUnits, {
+ // those values are to avoid errors. this function is uniquely used by
+ viewBoxWidth: 100,
+ viewBoxHeight: 100,
+ });
return new fabric.Gradient(options);
}
});
@@ -5971,47 +6176,33 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
/**
* @private
*/
- function _convertPercentUnitsToValues(object, options, gradientUnits) {
- var propValue, addFactor = 0, multFactor = 1, ellipseMatrix = '';
- for (var prop in options) {
- if (options[prop] === 'Infinity') {
- options[prop] = 1;
- }
- else if (options[prop] === '-Infinity') {
- options[prop] = 0;
+ function __convertPercentUnitsToValues(instance, options, svgOptions,
gradientUnits) {
+ var propValue, finalValue;
+ Object.keys(options).forEach(function(prop) {
+ propValue = options[prop];
+ if (propValue === 'Infinity') {
+ finalValue = 1;
}
- propValue = parseFloat(options[prop], 10);
- if (typeof options[prop] === 'string' &&
/^(\d+\.\d+)%|(\d+)%$/.test(options[prop])) {
- multFactor = 0.01;
+ else if (propValue === '-Infinity') {
+ finalValue = 0;
}
else {
- multFactor = 1;
- }
- if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
- multFactor *= gradientUnits === 'objectBoundingBox' ? object.width : 1;
- addFactor = gradientUnits === 'objectBoundingBox' ? object.left || 0 :
0;
- }
- else if (prop === 'y1' || prop === 'y2') {
- multFactor *= gradientUnits === 'objectBoundingBox' ? object.height :
1;
- addFactor = gradientUnits === 'objectBoundingBox' ? object.top || 0 :
0;
- }
- options[prop] = propValue * multFactor + addFactor;
- }
- if (object.type === 'ellipse' &&
- options.r2 !== null &&
- gradientUnits === 'objectBoundingBox' &&
- object.rx !== object.ry) {
-
- var scaleFactor = object.ry / object.rx;
- ellipseMatrix = ' scale(1, ' + scaleFactor + ')';
- if (options.y1) {
- options.y1 /= scaleFactor;
- }
- if (options.y2) {
- options.y2 /= scaleFactor;
+ finalValue = parseFloat(options[prop], 10);
+ if (typeof propValue === 'string' &&
/^(\d+\.\d+)%|(\d+)%$/.test(propValue)) {
+ finalValue *= 0.01;
+ if (gradientUnits === 'pixels') {
+ // then we need to fix those percentages here in svg parsing
+ if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
+ finalValue *= svgOptions.viewBoxWidth || svgOptions.width;
+ }
+ if (prop === 'y1' || prop === 'y2') {
+ finalValue *= svgOptions.viewBoxHeight || svgOptions.height;
+ }
+ }
+ }
}
- }
- return ellipseMatrix;
+ options[prop] = finalValue;
+ });
}
})();
@@ -6692,12 +6883,20 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
if (!this._isRetinaScaling()) {
return;
}
- this.lowerCanvasEl.setAttribute('width', this.width *
fabric.devicePixelRatio);
- this.lowerCanvasEl.setAttribute('height', this.height *
fabric.devicePixelRatio);
+ var scaleRatio = fabric.devicePixelRatio;
+ this.__initRetinaScaling(scaleRatio, this.lowerCanvasEl,
this.contextContainer);
+ if (this.upperCanvasEl) {
+ this.__initRetinaScaling(scaleRatio, this.upperCanvasEl,
this.contextTop);
+ }
+ },
- this.contextContainer.scale(fabric.devicePixelRatio,
fabric.devicePixelRatio);
+ __initRetinaScaling: function(scaleRatio, canvas, context) {
+ canvas.setAttribute('width', this.width * scaleRatio);
+ canvas.setAttribute('height', this.height * scaleRatio);
+ context.scale(scaleRatio, scaleRatio);
},
+
/**
* Calculates canvas element offset relative to the document
* This method is also attached as "resize" event handler of window
@@ -7429,12 +7628,9 @@ fabric.ElementsParser = function(elements, callback,
options, reviver, parsingOp
? fill.toLive(ctx, this)
: fill;
if (needsVpt) {
- ctx.transform(
- v[0], v[1], v[2], v[3],
- v[4] + (fill.offsetX || 0),
- v[5] + (fill.offsetY || 0)
- );
+ ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
}
+ ctx.transform(1, 0, 0, 1, fill.offsetX || 0, fill.offsetY || 0);
var m = fill.gradientTransform || fill.patternTransform;
m && ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
ctx.fill();
@@ -8397,13 +8593,18 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends
fabric.BaseBrush.prototype
return;
}
- var ctx = this.canvas.contextTop,
- zoom = this.canvas.getZoom();
+ var canvas = this.canvas,
+ shadow = this.shadow,
+ ctx = canvas.contextTop,
+ zoom = canvas.getZoom();
+ if (canvas && canvas._isRetinaScaling()) {
+ zoom *= fabric.devicePixelRatio;
+ }
- ctx.shadowColor = this.shadow.color;
- ctx.shadowBlur = this.shadow.blur * zoom;
- ctx.shadowOffsetX = this.shadow.offsetX * zoom;
- ctx.shadowOffsetY = this.shadow.offsetY * zoom;
+ ctx.shadowColor = shadow.color;
+ ctx.shadowBlur = shadow.blur * zoom;
+ ctx.shadowOffsetX = shadow.offsetX * zoom;
+ ctx.shadowOffsetY = shadow.offsetY * zoom;
},
needsFullRender: function() {
@@ -8706,7 +8907,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends
fabric.BaseBrush.prototype
var path = this.createPath(pathData);
this.canvas.clearContext(this.canvas.contextTop);
this.canvas.add(path);
- this.canvas.renderAll();
+ this.canvas.requestRenderAll();
path.setCoords();
this._resetShadow();
@@ -9471,6 +9672,26 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
fireMiddleClick: false,
/**
+ * Keep track of the subTargets for Mouse Events
+ * @type fabric.Object[]
+ */
+ targets: [],
+
+ /**
+ * Keep track of the hovered target
+ * @type fabric.Object
+ * @private
+ */
+ _hoveredTarget: null,
+
+ /**
+ * hold the list of nested targets hovered
+ * @type fabric.Object[]
+ * @private
+ */
+ _hoveredTargets: [],
+
+ /**
* @private
*/
_initInteractive: function() {
@@ -10047,7 +10268,7 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
transform.newScaleX = scaleX;
transform.newScaleY = scaleY;
- if (by === 'x' && target instanceof fabric.Textbox) {
+ if (fabric.Textbox && by === 'x' && target instanceof fabric.Textbox) {
var w = target.width * (localMouse.x / _dim.x);
if (w >= target.getMinWidth()) {
scaled = w !== target.width;
@@ -10467,6 +10688,12 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
pointer = this.restorePointerVpt(pointer);
}
+ var retinaScaling = this.getRetinaScaling();
+ if (retinaScaling !== 1) {
+ pointer.x /= retinaScaling;
+ pointer.y /= retinaScaling;
+ }
+
if (boundsWidth === 0 || boundsHeight === 0) {
// If bounds are not available (i.e. not visible), do not apply scale.
cssScale = { width: 1, height: 1 };
@@ -10489,22 +10716,24 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @throws {CANVAS_INIT_ERROR} If canvas can not be initialized
*/
_createUpperCanvas: function () {
- var lowerCanvasClass =
this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/, '');
+ var lowerCanvasClass =
this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/, ''),
+ lowerCanvasEl = this.lowerCanvasEl, upperCanvasEl =
this.upperCanvasEl;
// there is no need to create a new upperCanvas element if we have
already one.
- if (this.upperCanvasEl) {
- this.upperCanvasEl.className = '';
+ if (upperCanvasEl) {
+ upperCanvasEl.className = '';
}
else {
- this.upperCanvasEl = this._createCanvasElement();
+ upperCanvasEl = this._createCanvasElement();
+ this.upperCanvasEl = upperCanvasEl;
}
- fabric.util.addClass(this.upperCanvasEl, 'upper-canvas ' +
lowerCanvasClass);
+ fabric.util.addClass(upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);
- this.wrapperEl.appendChild(this.upperCanvasEl);
+ this.wrapperEl.appendChild(upperCanvasEl);
- this._copyCanvasStyle(this.lowerCanvasEl, this.upperCanvasEl);
- this._applyCanvasStyle(this.upperCanvasEl);
- this.contextTop = this.upperCanvasEl.getContext('2d');
+ this._copyCanvasStyle(lowerCanvasEl, upperCanvasEl);
+ this._applyCanvasStyle(upperCanvasEl);
+ this.contextTop = upperCanvasEl.getContext('2d');
},
/**
@@ -10617,8 +10846,9 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
this.fire('selection:cleared', { target: obj });
obj.fire('deselected');
}
- if (this._hoveredTarget === obj) {
+ if (obj === this._hoveredTarget){
this._hoveredTarget = null;
+ this._hoveredTargets = [];
}
this.callSuper('_onObjectRemoved', obj);
},
@@ -11036,6 +11266,14 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
this.fire('mouse:out', { target: target, e: e });
this._hoveredTarget = null;
target && target.fire('mouseout', { e: e });
+
+ var _this = this;
+ this._hoveredTargets.forEach(function(_target){
+ _this.fire('mouse:out', { target: target, e: e });
+ _target && target.fire('mouseout', { e: e });
+ });
+ this._hoveredTargets = [];
+
if (this._iTextInstances) {
this._iTextInstances.forEach(function(obj) {
if (obj.isEditing) {
@@ -11059,6 +11297,7 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
if (!this.currentTransform && !this.findTarget(e)) {
this.fire('mouse:over', { target: null, e: e });
this._hoveredTarget = null;
+ this._hoveredTargets = [];
}
},
@@ -11684,13 +11923,26 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @private
*/
_fireOverOutEvents: function(target, e) {
+ var _hoveredTarget = this._hoveredTarget,
+ _hoveredTargets = this._hoveredTargets, targets = this.targets,
+ length = Math.max(_hoveredTargets.length, targets.length);
+
this.fireSyntheticInOutEvents(target, e, {
- targetName: '_hoveredTarget',
- canvasEvtOut: 'mouse:out',
+ oldTarget: _hoveredTarget,
evtOut: 'mouseout',
- canvasEvtIn: 'mouse:over',
+ canvasEvtOut: 'mouse:out',
evtIn: 'mouseover',
+ canvasEvtIn: 'mouse:over',
});
+ for (var i = 0; i < length; i++){
+ this.fireSyntheticInOutEvents(targets[i], e, {
+ oldTarget: _hoveredTargets[i],
+ evtOut: 'mouseout',
+ evtIn: 'mouseover',
+ });
+ }
+ this._hoveredTarget = target;
+ this._hoveredTargets = this.targets.concat();
},
/**
@@ -11700,11 +11952,23 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @private
*/
_fireEnterLeaveEvents: function(target, e) {
+ var _draggedoverTarget = this._draggedoverTarget,
+ _hoveredTargets = this._hoveredTargets, targets = this.targets,
+ length = Math.max(_hoveredTargets.length, targets.length);
+
this.fireSyntheticInOutEvents(target, e, {
- targetName: '_draggedoverTarget',
+ oldTarget: _draggedoverTarget,
evtOut: 'dragleave',
evtIn: 'dragenter',
});
+ for (var i = 0; i < length; i++) {
+ this.fireSyntheticInOutEvents(targets[i], e, {
+ oldTarget: _hoveredTargets[i],
+ evtOut: 'dragleave',
+ evtIn: 'dragenter',
+ });
+ }
+ this._draggedoverTarget = target;
},
/**
@@ -11720,12 +11984,11 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @private
*/
fireSyntheticInOutEvents: function(target, e, config) {
- var inOpt, outOpt, oldTarget = this[config.targetName], outFires,
inFires,
+ var inOpt, outOpt, oldTarget = config.oldTarget, outFires, inFires,
targetChanged = oldTarget !== target, canvasEvtIn =
config.canvasEvtIn, canvasEvtOut = config.canvasEvtOut;
if (targetChanged) {
inOpt = { e: e, target: target, previousTarget: oldTarget };
outOpt = { e: e, target: oldTarget, nextTarget: target };
- this[config.targetName] = target;
}
inFires = target && targetChanged;
outFires = oldTarget && targetChanged;
@@ -11890,6 +12153,13 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
&& target._findTargetCorner(this.getPointer(e, true));
if (!corner) {
+ if (target.subTargetCheck){
+ // hoverCursor should come from top-most subTarget,
+ // so we walk the array backwards
+ this.targets.concat().reverse().map(function(_target){
+ hoverCursor = _target.hoverCursor || hoverCursor;
+ });
+ }
this.setCursor(hoverCursor);
}
else {
@@ -12009,6 +12279,7 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
if (activeSelection.contains(target)) {
activeSelection.removeWithUpdate(target);
this._hoveredTarget = target;
+ this._hoveredTargets = this.targets.concat();
if (activeSelection.size() === 1) {
// activate last remaining object
this._setActiveObject(activeSelection.item(0), e);
@@ -12017,6 +12288,7 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
else {
activeSelection.addWithUpdate(target);
this._hoveredTarget = activeSelection;
+ this._hoveredTargets = this.targets.concat();
}
this._fireSelectionEvents(currentActiveObjects, e);
},
@@ -12027,6 +12299,9 @@ fabric.PatternBrush =
fabric.util.createClass(fabric.PencilBrush, /** @lends fab
_createActiveSelection: function(target, e) {
var currentActives = this.getActiveObjects(), group =
this._createGroup(target);
this._hoveredTarget = group;
+ // ISSUE 4115: should we consider subTargets here?
+ // this._hoveredTargets = [];
+ // this._hoveredTargets = this.targets.concat();
this._setActiveObject(group, e);
this._fireSelectionEvents(currentActives, e);
},
@@ -13846,7 +14121,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Function} alternative function to call if browser does not
support lineDash
*/
_setLineDash: function(ctx, dashArray, alternative) {
- if (!dashArray) {
+ if (!dashArray || dashArray.length === 0) {
return;
}
// Spec requires the concatenation of two copies the dash list when the
number of elements is odd
@@ -13859,9 +14134,6 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
else {
alternative && alternative(ctx);
}
- if (this.strokeUniform) {
- ctx.setLineDash(ctx.getLineDash().map(function(value) { return value *
ctx.lineWidth; }));
- }
},
/**
@@ -13952,7 +14224,13 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
var t = filler.gradientTransform || filler.patternTransform;
var offsetX = -this.width / 2 + filler.offsetX || 0,
offsetY = -this.height / 2 + filler.offsetY || 0;
- ctx.translate(offsetX, offsetY);
+
+ if (filler.gradientUnits === 'percentage') {
+ ctx.transform(this.width, 0, 0, this.height, offsetX, offsetY);
+ }
+ else {
+ ctx.transform(1, 0, 0, 1, offsetX, offsetY);
+ }
if (t) {
ctx.transform(t[0], t[1], t[2], t[3], t[4], t[5]);
}
@@ -14005,6 +14283,10 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
ctx.restore();
},
+ /**
+ * @private
+ * @param {CanvasRenderingContext2D} ctx Context to render on
+ */
_renderStroke: function(ctx) {
if (!this.stroke || this.strokeWidth === 0) {
return;
@@ -14019,12 +14301,57 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
}
this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
- this._applyPatternGradientTransform(ctx, this.stroke);
+ if (this.stroke.toLive && this.stroke.gradientUnits === 'percentage') {
+ // need to transform gradient in a pattern.
+ // this is a slow process. If you are hitting this codepath, and the
object
+ // is not using caching, you should consider switching it on.
+ // we need a canvas as big as the current object caching canvas.
+ this._applyPatternForTransformedGradient(ctx, this.stroke);
+ }
+ else {
+ this._applyPatternGradientTransform(ctx, this.stroke);
+ }
ctx.stroke();
ctx.restore();
},
/**
+ * This function try to patch the missing gradientTransform on canvas
gradients.
+ * transforming a context to transform the gradient, is going to transform
the stroke too.
+ * we want to transform the gradient but not the stroke operation, so we
create
+ * a transformed gradient on a pattern and then we use the pattern instead
of the gradient.
+ * this method has drwabacks: is slow, is in low resolution, needs a patch
for when the size
+ * is limited.
+ * @private
+ * @param {CanvasRenderingContext2D} ctx Context to render on
+ * @param {fabric.Gradient} filler a fabric gradient instance
+ */
+ _applyPatternForTransformedGradient: function(ctx, filler) {
+ var dims = this._limitCacheSize(this._getCacheCanvasDimensions()),
+ pCanvas = fabric.util.createCanvasElement(), pCtx, retinaScaling =
this.canvas.getRetinaScaling(),
+ width = dims.x / this.scaleX / retinaScaling, height = dims.y /
this.scaleY / retinaScaling;
+ pCanvas.width = width;
+ pCanvas.height = height;
+ pCtx = pCanvas.getContext('2d');
+ pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0);
pCtx.lineTo(width, height);
+ pCtx.lineTo(0, height); pCtx.closePath();
+ pCtx.translate(width / 2, height / 2);
+ pCtx.scale(
+ dims.zoomX / this.scaleX / retinaScaling,
+ dims.zoomY / this.scaleY / retinaScaling
+ );
+ this._applyPatternGradientTransform(pCtx, filler);
+ pCtx.fillStyle = filler.toLive(ctx);
+ pCtx.fill();
+ ctx.translate(-this.width / 2 - this.strokeWidth / 2, -this.height / 2 -
this.strokeWidth / 2);
+ ctx.scale(
+ retinaScaling * this.scaleX / dims.zoomX,
+ retinaScaling * this.scaleY / dims.zoomY
+ );
+ ctx.strokeStyle = pCtx.createPattern(pCanvas, 'no-repeat');
+ },
+
+ /**
* This function is an helper for svg import. it returns the center of the
object in the svg
* untransformed coordinates
* @private
@@ -14138,9 +14465,10 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
options || (options = { });
var utils = fabric.util, origParams = utils.saveObjectTransform(this),
+ originalGroup = this.group,
originalShadow = this.shadow, abs = Math.abs,
multiplier = (options.multiplier || 1) *
(options.enableRetinaScaling ? fabric.devicePixelRatio : 1);
-
+ delete this.group;
if (options.withoutTransform) {
utils.resetObjectTransform(this);
}
@@ -14162,6 +14490,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
else {
scaling = this.getObjectScaling();
}
+ // consider non scaling shadow.
shadowOffset.x = 2 * Math.round(abs(shadow.offsetX) + shadowBlur) *
(abs(scaling.scaleX));
shadowOffset.y = 2 * Math.round(abs(shadow.offsetY) + shadowBlur) *
(abs(scaling.scaleY));
}
@@ -14184,6 +14513,9 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
var canvasEl = canvas.toCanvasElement(multiplier || 1, options);
this.shadow = originalShadow;
this.canvas = originalCanvas;
+ if (originalGroup) {
+ this.group = originalGroup;
+ }
this.set(origParams).setCoords();
// canvas.dispose will call image.dispose that will nullify the elements
// since this canvas is a simple element for the process, we remove
references
@@ -14244,6 +14576,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
/**
* Sets gradient (fill or stroke) of an object
+ * percentages for x1,x2,y1,y2,r1,r2 together with gradientUnits 'pixels',
are not supported.
* <b>Backwards incompatibility note:</b> This method was named
"setGradientFill" until v1.1.0
* @param {String} property Property name 'stroke' or 'fill'
* @param {Object} [options] Options object
@@ -14258,6 +14591,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Object} [options.gradientTransform] transformMatrix for gradient
* @return {fabric.Object} thisArg
* @chainable
+ * @deprecated since 3.4.0
* @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo}
* @example <caption>Set linear gradient</caption>
* object.setGradient('fill', {
@@ -14302,7 +14636,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
x2: options.x2,
y2: options.y2
};
-
+ gradient.gradientUnits = options.gradientUnits || 'pixels';
if (options.r1 || options.r2) {
gradient.coords.r1 = options.r1;
gradient.coords.r2 = options.r2;
@@ -14324,6 +14658,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Function} [callback] Callback to invoke when image set as a
pattern
* @return {fabric.Object} thisArg
* @chainable
+ * @deprecated since 3.5.0
* @see {@link http://jsfiddle.net/fabricjs/QT3pa/|jsFiddle demo}
* @example <caption>Set pattern</caption>
* object.setPatternFill({
@@ -14344,6 +14679,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Number} [options.offsetY=0] Shadow vertical offset
* @return {fabric.Object} thisArg
* @chainable
+ * @deprecated since 3.5.0
* @see {@link http://jsfiddle.net/fabricjs/7gvJG/|jsFiddle demo}
* @example <caption>Set shadow with string notation</caption>
* object.setShadow('2px 2px 10px rgba(0,0,0,0.2)');
@@ -14365,6 +14701,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* Sets "color" of an instance (alias of `set('fill', …)`)
* @param {String} color Color value
* @return {fabric.Object} thisArg
+ * @deprecated since 3.5.0
* @chainable
*/
setColor: function(color) {
@@ -14531,7 +14868,6 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @type Number
*/
fabric.Object.__uid = 0;
-
})(typeof exports !== 'undefined' ? exports : this);
@@ -15272,11 +15608,7 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @return {Array} rotation matrix for the object
*/
_calcRotateMatrix: function() {
- if (this.angle) {
- var theta = degreesToRadians(this.angle), cos =
fabric.util.cos(theta), sin = fabric.util.sin(theta);
- return [cos, sin, -sin, cos, 0, 0];
- }
- return fabric.iMatrix.concat();
+ return fabric.util.calcRotateMatrix(this);
},
/**
@@ -15321,41 +15653,41 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
return matrix;
},
+ /**
+ * calculate transform matrix that represents the current transformations
from the
+ * object's properties, this matrix does not include the group
transformation
+ * @return {Array} transform matrix for the object
+ */
calcOwnMatrix: function() {
var key = this.transformMatrixKey(true), cache = this.ownMatrixCache ||
(this.ownMatrixCache = {});
if (cache.key === key) {
return cache.value;
}
- var matrix = this._calcTranslateMatrix(),
- rotateMatrix,
- dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX,
this.skewY, true);
- if (this.angle) {
- rotateMatrix = this._calcRotateMatrix();
- matrix = multiplyMatrices(matrix, rotateMatrix);
- }
- matrix = multiplyMatrices(matrix, dimensionMatrix);
+ var tMatrix = this._calcTranslateMatrix();
+ this.translateX = tMatrix[4];
+ this.translateY = tMatrix[5];
cache.key = key;
- cache.value = matrix;
- return matrix;
+ cache.value = fabric.util.composeMatrix(this);
+ return cache.value;
},
+ /*
+ * Calculate object dimensions from its properties
+ * @private
+ * @deprecated since 3.4.0, please use
fabric.util._calcDimensionsTransformMatrix
+ * not including or including flipX, flipY to emulate the flipping boolean
+ * @return {Object} .x width dimension
+ * @return {Object} .y height dimension
+ */
_calcDimensionsTransformMatrix: function(skewX, skewY, flipping) {
- var skewMatrix,
- scaleX = this.scaleX * (flipping && this.flipX ? -1 : 1),
- scaleY = this.scaleY * (flipping && this.flipY ? -1 : 1),
- scaleMatrix = [scaleX, 0, 0, scaleY, 0, 0];
- if (skewX) {
- skewMatrix = [1, 0, Math.tan(degreesToRadians(skewX)), 1];
- scaleMatrix = multiplyMatrices(scaleMatrix, skewMatrix, true);
- }
- if (skewY) {
- skewMatrix = [1, Math.tan(degreesToRadians(skewY)), 0, 1];
- scaleMatrix = multiplyMatrices(scaleMatrix, skewMatrix, true);
- }
- return scaleMatrix;
+ return fabric.util.calcDimensionsMatrix({
+ skewX: skewX,
+ skewY: skewY,
+ scaleX: this.scaleX * (flipping && this.flipX ? -1 : 1),
+ scaleY: this.scaleY * (flipping && this.flipY ? -1 : 1)
+ });
},
-
/*
* Calculate object dimensions from its properties
* @private
@@ -15419,12 +15751,13 @@
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
x: dimX,
y: dimY
}],
- i, transformMatrix = this._calcDimensionsTransformMatrix(skewX,
skewY, false),
- bbox;
- for (i = 0; i < points.length; i++) {
- points[i] = fabric.util.transformPoint(points[i], transformMatrix);
- }
- bbox = fabric.util.makeBoundingBoxFromPoints(points);
+ transformMatrix = fabric.util.calcDimensionsMatrix({
+ scaleX: this.scaleX,
+ scaleY: this.scaleY,
+ skewX: this.skewX,
+ skewY: this.skewY,
+ }),
+ bbox = fabric.util.makeBoundingBoxFromPoints(points,
transformMatrix);
return this._finalizeDimensions(bbox.width, bbox.height);
},
@@ -16113,7 +16446,11 @@ fabric.util.object.extend(fabric.Object.prototype, /**
@lends fabric.Object.prot
drawBordersInGroup: function(ctx, options, styleOverride) {
styleOverride = styleOverride || {};
var p = this._getNonTransformedDimensions(),
- matrix = fabric.util.customTransformMatrix(options.scaleX,
options.scaleY, options.skewX),
+ matrix = fabric.util.composeMatrix({
+ scaleX: options.scaleX,
+ scaleY: options.scaleY,
+ skewX: options.skewX
+ }),
wh = fabric.util.transformPoint(p, matrix),
strokeWidth = 1 / this.borderScaleFactor,
width = wh.x + strokeWidth,
@@ -18459,7 +18796,7 @@ fabric.util.object.extend(fabric.Object.prototype, /**
@lends fabric.Object.prot
coords = [],
currentPath,
parsed,
- re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig,
+ re = fabric.rePathCommand,
match,
coordsStr;
@@ -18909,7 +19246,7 @@ fabric.util.object.extend(fabric.Object.prototype, /**
@lends fabric.Object.prot
strokeWidth: 0,
/**
- * Indicates if click events should also check for subtargets
+ * Indicates if click, mouseover, mouseout events & hoverCursor should
also check for subtargets
* @type Boolean
* @default
*/
@@ -19442,7 +19779,19 @@ fabric.util.object.extend(fabric.Object.prototype, /**
@lends fabric.Object.prot
* @param {Function} [callback] Callback to invoke when an group instance is
created
*/
fabric.Group.fromObject = function(object, callback) {
- fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) {
+ var objects = object.objects,
+ options = fabric.util.object.clone(object, true);
+ delete options.objects;
+ if (typeof objects === 'string') {
+ // it has to be an url or something went wrong.
+ fabric.loadSVGFromURL(objects, function (elements) {
+ var group = fabric.util.groupSVGElements(elements, object, objects);
+ group.set(options);
+ callback && callback(group);
+ });
+ return;
+ }
+ fabric.util.enlivenObjects(objects, function(enlivenedObjects) {
fabric.util.enlivenObjects([object.clipPath], function(enlivedClipPath) {
var options = fabric.util.object.clone(object, true);
options.clipPath = enlivedClipPath[0];
@@ -20147,7 +20496,8 @@ fabric.util.object.extend(fabric.Object.prototype, /**
@lends fabric.Object.prot
},
/**
- * @private, needed to check if image needs resize
+ * needed to check if image needs resize
+ * @private
*/
_needsResize: function() {
var scale = this.getTotalObjectScaling();
@@ -27019,15 +27369,17 @@ fabric.Image.filters.BaseFilter.fromObject =
function(object, callback) {
* @return {Number} Index of the beginning or end of a word
*/
searchWordBoundary: function(selectionStart, direction) {
- var index = this._reSpace.test(this._text[selectionStart]) ?
selectionStart - 1 : selectionStart,
- _char = this._text[index],
- reNonWord = /[ \n\.,;!\?\-]/;
+ var text = this._text,
+ index = this._reSpace.test(text[selectionStart]) ?
selectionStart - 1 : selectionStart,
+ _char = text[index],
+ // wrong
+ reNonWord = fabric.reNonWord;
- while (!reNonWord.test(_char) && index > 0 && index < this._text.length)
{
+ while (!reNonWord.test(_char) && index > 0 && index < text.length) {
index += direction;
- _char = this._text[index];
+ _char = text[index];
}
- if (reNonWord.test(_char) && _char !== '\n') {
+ if (reNonWord.test(_char)) {
index += direction === 1 ? 0 : 1;
}
return index;
@@ -27268,9 +27620,10 @@ fabric.Image.filters.BaseFilter.fromObject =
function(object, callback) {
x: boundaries.left + leftOffset,
y: boundaries.top + boundaries.topOffset + charHeight
},
+ retinaScaling = this.canvas.getRetinaScaling(),
upperCanvas = this.canvas.upperCanvasEl,
- upperCanvasWidth = upperCanvas.width,
- upperCanvasHeight = upperCanvas.height,
+ upperCanvasWidth = upperCanvas.width / retinaScaling,
+ upperCanvasHeight = upperCanvas.height / retinaScaling,
maxWidth = upperCanvasWidth - charHeight,
maxHeight = upperCanvasHeight - charHeight,
scaleX = upperCanvas.clientWidth / upperCanvasWidth,
@@ -27725,15 +28078,31 @@ fabric.util.object.extend(fabric.IText.prototype, /**
@lends fabric.IText.protot
},
/**
+ * Default handler for double click, select a word
+ */
+ doubleClickHandler: function(options) {
+ if (!this.isEditing) {
+ return;
+ }
+ this.selectWord(this.getSelectionStartFromPointer(options.e));
+ },
+
+ /**
+ * Default handler for triple click, select a line
+ */
+ tripleClickHandler: function(options) {
+ if (!this.isEditing) {
+ return;
+ }
+ this.selectLine(this.getSelectionStartFromPointer(options.e));
+ },
+
+ /**
* Initializes double and triple click event handlers
*/
initClicks: function() {
- this.on('mousedblclick', function(options) {
- this.selectWord(this.getSelectionStartFromPointer(options.e));
- });
- this.on('tripleclick', function(options) {
- this.selectLine(this.getSelectionStartFromPointer(options.e));
- });
+ this.on('mousedblclick', this.doubleClickHandler);
+ this.on('tripleclick', this.tripleClickHandler);
},
/**
@@ -27771,9 +28140,9 @@ fabric.util.object.extend(fabric.IText.prototype, /**
@lends fabric.IText.protot
if (!this.canvas || !this.editable || (options.e.button &&
options.e.button !== 1)) {
return;
}
- if (this === this.canvas._activeObject) {
- this.selected = true;
- }
+ // we want to avoid that an object that was selected and then becomes
unselectable,
+ // may trigger editing mode in some way.
+ this.selected = this === this.canvas._activeObject;
},
/**
@@ -28982,9 +29351,11 @@ fabric.util.object.extend(fabric.IText.prototype, /**
@lends fabric.IText.protot
* @return {Boolean}
*/
isEmptyStyles: function(lineIndex) {
- var offset = 0, nextLineIndex = lineIndex + 1, nextOffset, obj,
shouldLimit = false;
- var map = this._styleMap[lineIndex];
- var mapNextLine = this._styleMap[lineIndex + 1];
+ if (!this.styles) {
+ return true;
+ }
+ var offset = 0, nextLineIndex = lineIndex + 1, nextOffset, obj,
shouldLimit = false,
+ map = this._styleMap[lineIndex], mapNextLine =
this._styleMap[lineIndex + 1];
if (map) {
lineIndex = map.line;
offset = map.offset;
diff --git
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/raw-player.js
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/raw-player.js
index 3e035af..82fbb0a 100644
---
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/raw-player.js
+++
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/raw-player.js
@@ -1,7 +1,7 @@
/* Licensed under the Apache License, Version 2.0 (the "License")
http://www.apache.org/licenses/LICENSE-2.0 */
var Player = (function() {
const player = {}, mainColor = '#ff6600', rad = 20;
- let trg, rectPause1, rectPause2, play, cProgress, progress;
+ let trg, circle, rectPause1, rectPause2, play, cProgress, progress;
function _sendStatus(g, _paused, _pos) {
g.status.paused = _paused;
@@ -44,16 +44,15 @@ var Player = (function() {
, stroke: mainColor
, fill: mainColor
});
- play = new fabric.Group([
- new fabric.Circle({
- left: rad
- , top: _o.height - 3 * rad
- , radius: rad
- , stroke: mainColor
- , strokeWidth: 2
- , fill: null
- })
- , trg, rectPause1, rectPause2]
+ circle = new fabric.Circle({
+ left: rad
+ , top: _o.height - 3 * rad
+ , radius: rad
+ , stroke: mainColor
+ , strokeWidth: 2
+ , fill: null
+ });
+ play = new fabric.Group([circle, trg, rectPause1, rectPause2]
, {
objectCaching: false
, visible: false
@@ -152,22 +151,15 @@ var Player = (function() {
}
});
play.on({
- /*
- *
https://github.com/kangax/fabric.js/issues/4115
- *
'mouseover': function() {
- circle1.set({strokeWidth: 4});
+ circle.set({strokeWidth: 4});
canvas.requestRenderAll();
}
, 'mouseout': function() {
- circle1.set({
- left: pos.left
- , top: pos.top
- , strokeWidth: 2
- });
+ circle.set({strokeWidth: 2});
canvas.requestRenderAll();
}
- , */'mousedown': function () {
+ , 'mousedown': function () {
play.set({
left: pos.left + 3
, top: pos.top + 3