mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-04-15 11:50:59 +00:00
Initial implementation of gradients. Work in progress (but demo page now has working "gradientify" button). Still need to add tests, and make sure gradient-based fills on SVG elements are parsed/set properly.
This commit is contained in:
parent
6fa84aba5e
commit
a40e9cd610
7 changed files with 341 additions and 2 deletions
152
dist/all.js
vendored
152
dist/all.js
vendored
|
|
@ -2706,6 +2706,21 @@ fabric.util.animate = animate;
|
|||
return oStyle;
|
||||
};
|
||||
|
||||
function resolveGradients(instances) {
|
||||
for (var i = instances.length; i--; ) {
|
||||
var instanceFillValue = instances[i].get('fill');
|
||||
|
||||
if (/^url\(/.test(instanceFillValue)) {
|
||||
|
||||
var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);
|
||||
|
||||
if (fabric.gradientDefs[gradientId]) {
|
||||
instances[i].set('fill', fabric.gradientDefs[gradientId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of svg elements to corresponding fabric.* instances
|
||||
* @static
|
||||
|
|
@ -2723,6 +2738,7 @@ fabric.util.animate = animate;
|
|||
instances = instances.filter(function(el) {
|
||||
return el != null;
|
||||
});
|
||||
resolveGradients(instances);
|
||||
callback(instances);
|
||||
}
|
||||
}
|
||||
|
|
@ -2790,6 +2806,7 @@ fabric.util.animate = animate;
|
|||
|
||||
return function(doc, callback) {
|
||||
if (!doc) return;
|
||||
|
||||
var descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
|
||||
|
||||
var elements = descendants.filter(function(el) {
|
||||
|
|
@ -2822,6 +2839,8 @@ fabric.util.animate = animate;
|
|||
height: height
|
||||
};
|
||||
|
||||
fabric.gradientDefs = fabric.getGradientDefs(doc);
|
||||
|
||||
fabric.parseElements(elements, function(instances) {
|
||||
if (callback) {
|
||||
callback(instances, options);
|
||||
|
|
@ -2838,6 +2857,135 @@ fabric.util.animate = animate;
|
|||
});
|
||||
|
||||
})(this);
|
||||
(function() {
|
||||
|
||||
/** @namespace */
|
||||
|
||||
fabric.Gradient = {
|
||||
|
||||
/**
|
||||
* @method create
|
||||
* @static
|
||||
*/
|
||||
create: function(ctx, options) {
|
||||
options || (options = { });
|
||||
|
||||
var x1 = options.x1 || 0,
|
||||
y1 = options.y1 || 0,
|
||||
x2 = options.x2 || ctx.canvas.width,
|
||||
y2 = options.y2 || 0,
|
||||
colorStops = options.colorStops;
|
||||
|
||||
var gradient = ctx.createLinearGradient(x1, y1, x2, y2);
|
||||
for (var position in colorStops) {
|
||||
var colorValue = colorStops[position];
|
||||
gradient.addColorStop(position, colorValue);
|
||||
}
|
||||
return gradient;
|
||||
},
|
||||
|
||||
/**
|
||||
* @method fromElement
|
||||
* @static
|
||||
* @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
|
||||
*/
|
||||
fromElement: function(el, ctx) {
|
||||
|
||||
/**
|
||||
* @example:
|
||||
*
|
||||
* <linearGradient id="grad1">
|
||||
* <stop offset="0%" stop-color="white"/>
|
||||
* <stop offset="100%" stop-color="black"/>
|
||||
* </linearGradient>
|
||||
*
|
||||
*/
|
||||
|
||||
var colorStopEls = el.getElementsByTagName('stop'),
|
||||
el,
|
||||
offset,
|
||||
colorStops = { };
|
||||
|
||||
for (var i = colorStopEls.length; i--; ) {
|
||||
el = colorStopEls[i];
|
||||
offset = parseInt(el.getAttribute('offset'), 10) / 100;
|
||||
colorStops[offset] = el.getAttribute('stop-color');
|
||||
}
|
||||
|
||||
return fabric.Gradient.create(ctx, {
|
||||
x1: el.getAttribute('x1') || 0,
|
||||
y1: el.getAttribute('y1') || 0,
|
||||
x2: el.getAttribute('x2') || '100%',
|
||||
y2: el.getAttribute('y2') || 0,
|
||||
colorStops: colorStops
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @method forObject
|
||||
* @static
|
||||
*/
|
||||
forObject: function(obj, ctx, options) {
|
||||
options || (options = { });
|
||||
|
||||
_convertPercentUnitsToValues(obj, options);
|
||||
|
||||
var gradient = fabric.Gradient.create(ctx, {
|
||||
x1: options.x1 - (obj.width / 2),
|
||||
y1: options.y1 - (obj.height / 2),
|
||||
x2: options.x2 - (obj.width / 2),
|
||||
y2: options.y2 - (obj.height / 2),
|
||||
colorStops: options.colorStops
|
||||
});
|
||||
|
||||
return gradient;
|
||||
}
|
||||
};
|
||||
|
||||
function _convertPercentUnitsToValues(object, options) {
|
||||
for (var prop in options) {
|
||||
if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
|
||||
var percents = parseFloat(options[prop], 10);
|
||||
if (prop === 'x1' || prop === 'x2') {
|
||||
options[prop] = object.width * percents / 100;
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
options[prop] = object.height * percents / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an SVG document, returning all of the gradient declarations found in it
|
||||
* @static
|
||||
* @function
|
||||
* @memberOf fabric
|
||||
* @method getGradientDefs
|
||||
* @param {SVGDocument} doc SVG document to parse
|
||||
* @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition
|
||||
*/
|
||||
function getGradientDefs(doc) {
|
||||
var linearGradientEls = doc.getElementsByTagName('linearGradient'),
|
||||
radialGradientEls = doc.getElementsByTagName('radialGradient'),
|
||||
el,
|
||||
gradientDefs = { };
|
||||
|
||||
for (var i = linearGradientEls.length; i--; ) {
|
||||
el = linearGradientEls[i];
|
||||
gradientDefs[el.id] = fabric.Gradient.fromElement(el);
|
||||
}
|
||||
for (var i = radialGradientEls.length; i--; ) {
|
||||
el = radialGradientEls[i];
|
||||
gradientDefs[el.id] = fabric.Gradient.fromElement(el);
|
||||
}
|
||||
|
||||
return gradientDefs;
|
||||
}
|
||||
|
||||
fabric.getGradientDefs = getGradientDefs;
|
||||
|
||||
})();
|
||||
|
||||
(function(global) {
|
||||
|
||||
|
|
@ -7024,6 +7172,10 @@ fabric.util.animate = animate;
|
|||
*/
|
||||
toJSON: function() {
|
||||
return this.toObject();
|
||||
},
|
||||
|
||||
setGradientFill: function(ctx, options) {
|
||||
this.set('fill', fabric.Gradient.forObject(this, ctx, options));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ if (typeof console !== 'undefined') {
|
|||
|
||||
//= require "src/util"
|
||||
//= require "src/parser"
|
||||
//= require "src/gradient"
|
||||
|
||||
//= require "src/point.class"
|
||||
//= require "src/intersection.class"
|
||||
|
|
|
|||
129
src/gradient.js
Normal file
129
src/gradient.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
(function() {
|
||||
|
||||
/** @namespace */
|
||||
|
||||
fabric.Gradient = {
|
||||
|
||||
/**
|
||||
* @method create
|
||||
* @static
|
||||
*/
|
||||
create: function(ctx, options) {
|
||||
options || (options = { });
|
||||
|
||||
var x1 = options.x1 || 0,
|
||||
y1 = options.y1 || 0,
|
||||
x2 = options.x2 || ctx.canvas.width,
|
||||
y2 = options.y2 || 0,
|
||||
colorStops = options.colorStops;
|
||||
|
||||
var gradient = ctx.createLinearGradient(x1, y1, x2, y2);
|
||||
for (var position in colorStops) {
|
||||
var colorValue = colorStops[position];
|
||||
gradient.addColorStop(position, colorValue);
|
||||
}
|
||||
return gradient;
|
||||
},
|
||||
|
||||
/**
|
||||
* @method fromElement
|
||||
* @static
|
||||
* @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement
|
||||
*/
|
||||
fromElement: function(el, ctx) {
|
||||
|
||||
/**
|
||||
* @example:
|
||||
*
|
||||
* <linearGradient id="grad1">
|
||||
* <stop offset="0%" stop-color="white"/>
|
||||
* <stop offset="100%" stop-color="black"/>
|
||||
* </linearGradient>
|
||||
*
|
||||
*/
|
||||
|
||||
var colorStopEls = el.getElementsByTagName('stop'),
|
||||
el,
|
||||
offset,
|
||||
colorStops = { };
|
||||
|
||||
for (var i = colorStopEls.length; i--; ) {
|
||||
el = colorStopEls[i];
|
||||
offset = parseInt(el.getAttribute('offset'), 10) / 100;
|
||||
colorStops[offset] = el.getAttribute('stop-color');
|
||||
}
|
||||
|
||||
return fabric.Gradient.create(ctx, {
|
||||
x1: el.getAttribute('x1') || 0,
|
||||
y1: el.getAttribute('y1') || 0,
|
||||
x2: el.getAttribute('x2') || '100%',
|
||||
y2: el.getAttribute('y2') || 0,
|
||||
colorStops: colorStops
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @method forObject
|
||||
* @static
|
||||
*/
|
||||
forObject: function(obj, ctx, options) {
|
||||
options || (options = { });
|
||||
|
||||
_convertPercentUnitsToValues(obj, options);
|
||||
|
||||
var gradient = fabric.Gradient.create(ctx, {
|
||||
x1: options.x1 - (obj.width / 2),
|
||||
y1: options.y1 - (obj.height / 2),
|
||||
x2: options.x2 - (obj.width / 2),
|
||||
y2: options.y2 - (obj.height / 2),
|
||||
colorStops: options.colorStops
|
||||
});
|
||||
|
||||
return gradient;
|
||||
}
|
||||
};
|
||||
|
||||
function _convertPercentUnitsToValues(object, options) {
|
||||
for (var prop in options) {
|
||||
if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
|
||||
var percents = parseFloat(options[prop], 10);
|
||||
if (prop === 'x1' || prop === 'x2') {
|
||||
options[prop] = object.width * percents / 100;
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
options[prop] = object.height * percents / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an SVG document, returning all of the gradient declarations found in it
|
||||
* @static
|
||||
* @function
|
||||
* @memberOf fabric
|
||||
* @method getGradientDefs
|
||||
* @param {SVGDocument} doc SVG document to parse
|
||||
* @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition
|
||||
*/
|
||||
function getGradientDefs(doc) {
|
||||
var linearGradientEls = doc.getElementsByTagName('linearGradient'),
|
||||
radialGradientEls = doc.getElementsByTagName('radialGradient'),
|
||||
el,
|
||||
gradientDefs = { };
|
||||
|
||||
for (var i = linearGradientEls.length; i--; ) {
|
||||
el = linearGradientEls[i];
|
||||
gradientDefs[el.id] = fabric.Gradient.fromElement(el);
|
||||
}
|
||||
for (var i = radialGradientEls.length; i--; ) {
|
||||
el = radialGradientEls[i];
|
||||
gradientDefs[el.id] = fabric.Gradient.fromElement(el);
|
||||
}
|
||||
|
||||
return gradientDefs;
|
||||
}
|
||||
|
||||
fabric.getGradientDefs = getGradientDefs;
|
||||
|
||||
})();
|
||||
|
|
@ -1270,6 +1270,10 @@
|
|||
toJSON: function() {
|
||||
// delegate, not alias
|
||||
return this.toObject();
|
||||
},
|
||||
|
||||
setGradientFill: function(ctx, options) {
|
||||
this.set('fill', fabric.Gradient.forObject(this, ctx, options));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -285,6 +285,22 @@
|
|||
}
|
||||
return oStyle;
|
||||
};
|
||||
|
||||
function resolveGradients(instances) {
|
||||
for (var i = instances.length; i--; ) {
|
||||
var instanceFillValue = instances[i].get('fill');
|
||||
|
||||
if (/^url\(/.test(instanceFillValue)) {
|
||||
|
||||
// url(#grad1) --> grad1
|
||||
var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);
|
||||
|
||||
if (fabric.gradientDefs[gradientId]) {
|
||||
instances[i].set('fill', fabric.gradientDefs[gradientId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of svg elements to corresponding fabric.* instances
|
||||
|
|
@ -303,6 +319,7 @@
|
|||
instances = instances.filter(function(el) {
|
||||
return el != null;
|
||||
});
|
||||
resolveGradients(instances);
|
||||
callback(instances);
|
||||
}
|
||||
}
|
||||
|
|
@ -373,6 +390,7 @@
|
|||
|
||||
return function(doc, callback) {
|
||||
if (!doc) return;
|
||||
|
||||
var descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
|
||||
|
||||
var elements = descendants.filter(function(el) {
|
||||
|
|
@ -405,6 +423,8 @@
|
|||
width: width,
|
||||
height: height
|
||||
};
|
||||
|
||||
fabric.gradientDefs = fabric.getGradientDefs(doc);
|
||||
|
||||
fabric.parseElements(elements, function(instances) {
|
||||
if (callback) {
|
||||
|
|
|
|||
|
|
@ -355,4 +355,20 @@
|
|||
initAligningGuidelines(canvas);
|
||||
}
|
||||
|
||||
document.getElementById('gradientify').onclick = function() {
|
||||
var obj = canvas.getActiveObject();
|
||||
if (obj) {
|
||||
obj.setGradientFill(canvas.getContext(), {
|
||||
x2: (getRandomInt(0, 1) ? 0 : obj.width),
|
||||
y2: (getRandomInt(0, 1) ? 0 : obj.height),
|
||||
colorStops: {
|
||||
0: '#' + getRandomColor(),
|
||||
1: '#' + getRandomColor()
|
||||
}
|
||||
});
|
||||
canvas.renderAll();
|
||||
console.log(getRandomNum(0, 1));
|
||||
}
|
||||
};
|
||||
|
||||
})(this);
|
||||
|
|
@ -50,17 +50,25 @@
|
|||
|
||||
<p>Add <strong>SVG shapes</strong> to canvas:</p>
|
||||
<ul class="svg-shapes">
|
||||
<li><button class="shape" id="shape54"><strong>1</strong> path</button></li>
|
||||
<li><button class="shape" id="shape25"><strong>36</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape36"><strong>41</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape58"><strong>54</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape59"><strong>57</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape8"><strong>65</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape17"><strong>87</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape2"><strong>90</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape47"><strong>133</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape51"><strong>141</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape50"><strong>167</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape63"><strong>202</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape64"><strong>224</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape14"><strong>226</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape62"><strong>237</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape57"><strong>321</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape9"><strong>404</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape45"><strong>404</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape65"><strong>444</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape1"><strong>448</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape38"><strong>563</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape37"><strong>758</strong> paths</button></li>
|
||||
|
|
@ -75,16 +83,19 @@
|
|||
<li><button class="shape" id="shape21"><strong>1972</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape5"><strong>2208</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape40"><strong>2394</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape55"><strong>2499</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape4"><strong>2742</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape29"><strong>3103</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape30"><strong>3566</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape61"><strong>3685</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape6"><strong>3921</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape23"><strong>4418</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape42"><strong>4583</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape31"><strong>4768</strong> paths</button></li>
|
||||
<!-- <li><button class="shape" id="shape28"><strong>5378</strong> paths</button></li> -->
|
||||
<li><button class="shape" id="shape15"><strong>8325</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape22"><strong>9663</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape52"><strong>11285</strong> paths <em>(broken)</em></button></li>
|
||||
<!-- <li><button class="shape" id="shape52"><strong>11285</strong> paths</button></li> -->
|
||||
<li><button class="shape" id="shape41"><strong>12361</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape24"><strong>12866</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape27"><strong>13905</strong> paths</button></li>
|
||||
|
|
@ -94,7 +105,9 @@
|
|||
<li><button class="shape" id="shape35"><strong>19271</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape44"><strong>22375</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape48"><strong>41787</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape54"><strong>xx</strong> paths</button></li>
|
||||
<!--<li><button class="shape" id="shape56"><strong>xxx</strong> paths</button></li>-->
|
||||
<!-- <li><button class="shape" id="shape60"><strong>xxx</strong> paths</button></li> -->
|
||||
<li><button class="shape" id="shape66"><strong>xxx</strong> paths</button></li>
|
||||
</ul>
|
||||
|
||||
<ul>
|
||||
|
|
@ -115,6 +128,10 @@
|
|||
<li>
|
||||
<button id="lock-rotation">Lock rotation</button>
|
||||
</li>
|
||||
|
||||
<li style="margin-top:10px;">
|
||||
<button id="gradientify">Gradientify</button>
|
||||
</li>
|
||||
|
||||
<li style="margin-top:10px;">
|
||||
<button id="drawing-mode">Enter drawing mode</button>
|
||||
|
|
|
|||
Loading…
Reference in a new issue