mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Refactor GradientStop: Improve handling of optionally defined color and rampPoint.
Relates to https://github.com/paperjs/paper.js/issues/1001#issuecomment-197557990
This commit is contained in:
parent
0e658da104
commit
d93aca6b5c
6 changed files with 83 additions and 53 deletions
|
@ -607,7 +607,7 @@ var Color = Base.extend(new function() {
|
|||
// Default fallbacks: rgb, black
|
||||
this._type = type || 'rgb';
|
||||
// Define this Color's unique id in its own private id pool.
|
||||
// NOTE: This is required by SVG Export code!
|
||||
// NOTE: This is only required by SVG Export code!
|
||||
this._id = UID.get(Color);
|
||||
if (!components) {
|
||||
// Produce a components array now, and parse values. Even if no
|
||||
|
@ -856,7 +856,11 @@ var Color = Base.extend(new function() {
|
|||
}
|
||||
for (var i = 0, l = stops.length; i < l; i++) {
|
||||
var stop = stops[i];
|
||||
canvasGradient.addColorStop(stop._rampPoint,
|
||||
// Use the defined offset, and fall back to automatic linear
|
||||
// calculation.
|
||||
// NOTE: that if _rampPoint is 0 for the first entry, the fall
|
||||
// back will be so too.
|
||||
canvasGradient.addColorStop(stop._rampPoint || i / (l - 1),
|
||||
stop._color.toCanvasStyle());
|
||||
}
|
||||
return this._canvasStyle = canvasGradient;
|
||||
|
|
|
@ -72,10 +72,11 @@ var Gradient = Base.extend(/** @lends Gradient# */{
|
|||
stops = radial = null;
|
||||
if (!this._stops)
|
||||
this.setStops(stops || ['white', 'black']);
|
||||
if (this._radial == null)
|
||||
if (this._radial == null) {
|
||||
// Support old string type argument and new radial boolean.
|
||||
this.setRadial(typeof radial === 'string' && radial === 'radial'
|
||||
|| radial || false);
|
||||
}
|
||||
},
|
||||
|
||||
_serialize: function(options, dictionary) {
|
||||
|
@ -91,8 +92,9 @@ var Gradient = Base.extend(/** @lends Gradient# */{
|
|||
_changed: function() {
|
||||
// Loop through the gradient-colors that use this gradient and notify
|
||||
// them, so they can notify the items they belong to.
|
||||
for (var i = 0, l = this._owners && this._owners.length; i < l; i++)
|
||||
for (var i = 0, l = this._owners && this._owners.length; i < l; i++) {
|
||||
this._owners[i]._changed();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -122,8 +124,9 @@ var Gradient = Base.extend(/** @lends Gradient# */{
|
|||
*/
|
||||
clone: function() {
|
||||
var stops = [];
|
||||
for (var i = 0, l = this._stops.length; i < l; i++)
|
||||
for (var i = 0, l = this._stops.length; i < l; i++) {
|
||||
stops[i] = this._stops[i].clone();
|
||||
}
|
||||
return new Gradient(stops, this._radial);
|
||||
},
|
||||
|
||||
|
@ -138,23 +141,20 @@ var Gradient = Base.extend(/** @lends Gradient# */{
|
|||
},
|
||||
|
||||
setStops: function(stops) {
|
||||
// If this gradient already contains stops, first remove
|
||||
// this gradient as their owner.
|
||||
if (this.stops) {
|
||||
for (var i = 0, l = this._stops.length; i < l; i++)
|
||||
this._stops[i]._owner = undefined;
|
||||
}
|
||||
if (stops.length < 2)
|
||||
if (stops.length < 2) {
|
||||
throw new Error(
|
||||
'Gradient stop list needs to contain at least two stops.');
|
||||
this._stops = GradientStop.readAll(stops, 0, { clone: true });
|
||||
// Now reassign ramp points if they were not specified.
|
||||
for (var i = 0, l = this._stops.length; i < l; i++) {
|
||||
var stop = this._stops[i];
|
||||
stop._owner = this;
|
||||
if (stop._defaultRamp)
|
||||
stop.setRampPoint(i / (l - 1));
|
||||
}
|
||||
// If this gradient already contains stops, first remove their owner.
|
||||
var _stops = this._stops;
|
||||
if (_stops) {
|
||||
for (var i = 0, l = _stops.length; i < l; i++)
|
||||
_stops[i]._owner = undefined;
|
||||
}
|
||||
_stops = this._stops = GradientStop.readAll(stops, 0, { clone: true });
|
||||
// Now assign this gradient as the new gradients' owner.
|
||||
for (var i = 0, l = _stops.length; i < l; i++)
|
||||
_stops[i]._owner = this;
|
||||
this._changed();
|
||||
},
|
||||
|
||||
|
@ -182,13 +182,17 @@ var Gradient = Base.extend(/** @lends Gradient# */{
|
|||
equals: function(gradient) {
|
||||
if (gradient === this)
|
||||
return true;
|
||||
if (gradient && this._class === gradient._class
|
||||
&& this._stops.length === gradient._stops.length) {
|
||||
for (var i = 0, l = this._stops.length; i < l; i++) {
|
||||
if (!this._stops[i].equals(gradient._stops[i]))
|
||||
return false;
|
||||
if (gradient && this._class === gradient._class) {
|
||||
var stops1 = this._stops,
|
||||
stops2 = gradient._stops,
|
||||
length = stops1.length;
|
||||
if (length === stops2.length) {
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (!stops1[i].equals(stops2[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -23,28 +23,30 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{
|
|||
* Creates a GradientStop object.
|
||||
*
|
||||
* @param {Color} [color=new Color(0, 0, 0)] the color of the stop
|
||||
* @param {Number} [rampPoint=0] the position of the stop on the gradient
|
||||
* ramp as a value between 0 and 1
|
||||
* @param {Number} [rampPoint=null] the position of the stop on the gradient
|
||||
* ramp as a value between `0` and `1`; `null` or `undefined` for automatic
|
||||
* assignment.
|
||||
*/
|
||||
initialize: function GradientStop(arg0, arg1) {
|
||||
if (arg0) {
|
||||
var color, rampPoint;
|
||||
if (arg1 === undefined && Array.isArray(arg0)) {
|
||||
// [color, rampPoint]
|
||||
// (color, rampPoint)
|
||||
var color = arg0,
|
||||
rampPoint = arg1;
|
||||
if (typeof arg0 === 'object' && arg1 === undefined) {
|
||||
// Make sure the first entry in the array is not a number, in which
|
||||
// case the whole array would be a color, and the assignments would
|
||||
// already have occurred correctly above.
|
||||
if (Array.isArray(arg0) && typeof arg0[0] !== 'number') {
|
||||
// ([color, rampPoint])
|
||||
color = arg0[0];
|
||||
rampPoint = arg0[1];
|
||||
} else if (arg0.color) {
|
||||
// stop
|
||||
} else if ('color' in arg0 || 'rampPoint' in arg0) {
|
||||
// (stop)
|
||||
color = arg0.color;
|
||||
rampPoint = arg0.rampPoint;
|
||||
} else {
|
||||
// color, rampPoint
|
||||
color = arg0;
|
||||
rampPoint = arg1;
|
||||
}
|
||||
this.setColor(color);
|
||||
this.setRampPoint(rampPoint);
|
||||
}
|
||||
this.setColor(color);
|
||||
this.setRampPoint(rampPoint);
|
||||
},
|
||||
|
||||
// TODO: Do we really need to also clone the color here?
|
||||
|
@ -56,8 +58,10 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{
|
|||
},
|
||||
|
||||
_serialize: function(options, dictionary) {
|
||||
return Base.serialize([this._color, this._rampPoint], options, true,
|
||||
dictionary);
|
||||
var color = this._color,
|
||||
rampPoint = this._rampPoint;
|
||||
return Base.serialize(rampPoint == null ? [color] : [color, rampPoint],
|
||||
options, true, dictionary);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -115,8 +119,7 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{
|
|||
},
|
||||
|
||||
setRampPoint: function(rampPoint) {
|
||||
this._defaultRamp = rampPoint == null;
|
||||
this._rampPoint = rampPoint || 0;
|
||||
this._rampPoint = rampPoint;
|
||||
this._changed();
|
||||
},
|
||||
|
||||
|
@ -162,13 +165,13 @@ var GradientStop = Base.extend(/** @lends GradientStop# */{
|
|||
return this._color;
|
||||
},
|
||||
|
||||
setColor: function(color) {
|
||||
setColor: function(/* color */) {
|
||||
// Make sure newly set colors are cloned, since they can only have
|
||||
// one owner.
|
||||
this._color = Color.read(arguments);
|
||||
if (this._color === color)
|
||||
this._color = color.clone();
|
||||
this._color._owner = this;
|
||||
var color = Color.read(arguments, 0, { clone: true });
|
||||
if (color)
|
||||
color._owner = this;
|
||||
this._color = color;
|
||||
this._changed();
|
||||
},
|
||||
|
||||
|
|
|
@ -231,12 +231,14 @@ new function() {
|
|||
var stops = gradient._stops;
|
||||
for (var i = 0, l = stops.length; i < l; i++) {
|
||||
var stop = stops[i],
|
||||
offset = stop._rampPoint,
|
||||
stopColor = stop._color,
|
||||
alpha = stopColor.getAlpha();
|
||||
attrs = {
|
||||
offset: stop._rampPoint,
|
||||
'stop-color': stopColor.toCSS(true)
|
||||
};
|
||||
attrs = {};
|
||||
if (offset != null)
|
||||
attrs.offset = offset;
|
||||
if (stopColor)
|
||||
attrs['stop-color'] = stopColor.toCSS(true);
|
||||
// See applyStyle for an explanation of why there are separated
|
||||
// opacity / color attributes.
|
||||
if (alpha < 1)
|
||||
|
|
|
@ -222,3 +222,16 @@ test('Color#divide', function() {
|
|||
var color = new Color(1, 1, 1);
|
||||
equals(color.divide(4), new Color([0.25, 0.25, 0.25]));
|
||||
});
|
||||
|
||||
test('Gradient', function() {
|
||||
var stop1 = new GradientStop({ rampPoint: 0 });
|
||||
var stop2 = new GradientStop('red', 0.75);
|
||||
var stop3 = new GradientStop(['white', 1]);
|
||||
var gradient = new Gradient([stop1, stop2, stop3], true);
|
||||
equals(function() { return stop1.color; }, new Color(0, 0, 0));
|
||||
equals(function() { return stop2.color; }, new Color(1, 0, 0));
|
||||
equals(function() { return stop3.color; }, new Color(1, 1, 1));
|
||||
equals(function() { return stop1.rampPoint; }, 0);
|
||||
equals(function() { return stop2.rampPoint; }, 0.75);
|
||||
equals(function() { return stop3.rampPoint; }, 1);
|
||||
});
|
||||
|
|
|
@ -219,7 +219,11 @@ test('Color#importJSON()', function() {
|
|||
// that runs between the two points we defined earlier:
|
||||
fillColor: {
|
||||
gradient: {
|
||||
stops: ['yellow', 'red', 'blue']
|
||||
stops: [
|
||||
['yellow', 0],
|
||||
['red', 0.5],
|
||||
['blue', 1]
|
||||
]
|
||||
},
|
||||
origin: topLeft,
|
||||
destination: bottomRight
|
||||
|
|
Loading…
Reference in a new issue