mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Remove internal clamping of color values to facilitate proper mathematical calculations with colors.
Clamp only when producing CSS values. Closes #271.
This commit is contained in:
parent
bb77da22a8
commit
0dddd897ab
4 changed files with 45 additions and 63 deletions
|
@ -179,9 +179,6 @@ Base.inject(/** @lends Base# */{
|
|||
obj = Base.create(this.prototype);
|
||||
if (readIndex)
|
||||
obj.__read = true;
|
||||
// If options were provided, pass them on to the constructed object
|
||||
if (options)
|
||||
obj.__options = options;
|
||||
obj = obj.initialize.apply(obj, index > 0 || length < list.length
|
||||
? Array.prototype.slice.call(list, index, index + length)
|
||||
: list) || obj;
|
||||
|
@ -191,8 +188,6 @@ Base.inject(/** @lends Base# */{
|
|||
// last read() call
|
||||
list.__read = obj.__read;
|
||||
delete obj.__read;
|
||||
if (options)
|
||||
delete obj.__options;
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
|
|
@ -247,23 +247,20 @@ var Color = Base.extend(new function() {
|
|||
}
|
||||
return value;
|
||||
}
|
||||
: name === 'hue'
|
||||
? function(value) {
|
||||
// Keep negative values within modulo 360 too:
|
||||
return isNaN(value) ? 0
|
||||
: ((value % 360) + 360) % 360;
|
||||
: type === 'gradient'
|
||||
? function(/* value */) {
|
||||
return Point.read(arguments, 0, 0, {
|
||||
readNull: name === 'highlight',
|
||||
clone: true
|
||||
});
|
||||
}
|
||||
: type === 'gradient'
|
||||
? function(/* value */) {
|
||||
return Point.read(arguments, 0, 0, {
|
||||
readNull: name === 'highlight',
|
||||
clone: true
|
||||
});
|
||||
}
|
||||
: function(value) {
|
||||
return isNaN(value) ? 0
|
||||
: Math.min(Math.max(value, 0), 1);
|
||||
};
|
||||
: function(value) {
|
||||
// NOTE: We don't clamp values here, they're only
|
||||
// clamped once the actual CSS values are produced.
|
||||
// Gotta love the fact that isNaN(null) is false,
|
||||
// while isNaN(undefined) is true.
|
||||
return value == null || isNaN(value) ? 0 : value;
|
||||
};
|
||||
|
||||
this['get' + part] = function() {
|
||||
return this._type === type
|
||||
|
@ -401,7 +398,7 @@ var Color = Base.extend(new function() {
|
|||
* // the path and to position the gradient color:
|
||||
* var topLeft = view.center - [80, 80];
|
||||
* var bottomRight = view.center + [80, 80];
|
||||
*
|
||||
*
|
||||
* var path = new Path.Rectangle({
|
||||
* topLeft: topLeft,
|
||||
* bottomRight: bottomRight,
|
||||
|
@ -489,7 +486,6 @@ var Color = Base.extend(new function() {
|
|||
var slice = Array.prototype.slice,
|
||||
args = arguments,
|
||||
read = 0,
|
||||
parse = true,
|
||||
type,
|
||||
components,
|
||||
alpha,
|
||||
|
@ -520,8 +516,6 @@ var Color = Base.extend(new function() {
|
|||
}
|
||||
}
|
||||
if (!components) {
|
||||
// Only parse values if we're not told to not do so
|
||||
parse = !(this.__options && this.__options.dontParse);
|
||||
// Determine if there is a values array
|
||||
values = argType === 'number'
|
||||
? args
|
||||
|
@ -586,7 +580,7 @@ var Color = Base.extend(new function() {
|
|||
: 'rgb';
|
||||
// Convert to array and parse in one loop, for efficiency
|
||||
var properties = types[type];
|
||||
parsers = parse && componentParsers[type];
|
||||
parsers = componentParsers[type];
|
||||
this._components = components = [];
|
||||
for (var i = 0, l = properties.length; i < l; i++) {
|
||||
var value = arg[properties[i]];
|
||||
|
@ -600,8 +594,7 @@ var Color = Base.extend(new function() {
|
|||
radial: arg.radial
|
||||
};
|
||||
}
|
||||
if (parse)
|
||||
value = parsers[i].call(this, value);
|
||||
value = parsers[i].call(this, value);
|
||||
if (value != null)
|
||||
components[i] = value;
|
||||
}
|
||||
|
@ -623,9 +616,7 @@ var Color = Base.extend(new function() {
|
|||
this._components = components = [];
|
||||
var parsers = componentParsers[this._type];
|
||||
for (var i = 0, l = parsers.length; i < l; i++) {
|
||||
var value = values && values[i];
|
||||
if (parse)
|
||||
value = parsers[i].call(this, value);
|
||||
var value = parsers[i].call(this, values && values[i]);
|
||||
if (value != null)
|
||||
components[i] = value;
|
||||
}
|
||||
|
@ -815,13 +806,16 @@ var Color = Base.extend(new function() {
|
|||
// TODO: Support HSL / HSLA CSS3 colors directly, without conversion
|
||||
var components = this._convert('rgb'),
|
||||
alpha = hex || this._alpha == null ? 1 : this._alpha;
|
||||
function convert(val) {
|
||||
return Math.round((val < 0 ? 0 : val > 1 ? 1 : val) * 255);
|
||||
}
|
||||
components = [
|
||||
Math.round(components[0] * 255),
|
||||
Math.round(components[1] * 255),
|
||||
Math.round(components[2] * 255)
|
||||
convert(components[0]),
|
||||
convert(components[1]),
|
||||
convert(components[2])
|
||||
];
|
||||
if (alpha < 1)
|
||||
components.push(alpha);
|
||||
components.push(val < 0 ? 0 : val);
|
||||
return hex
|
||||
? '#' + ((1 << 24) + (components[0] << 16)
|
||||
+ (components[1] << 8)
|
||||
|
@ -1119,48 +1113,33 @@ var Color = Base.extend(new function() {
|
|||
}
|
||||
});
|
||||
}, new function() {
|
||||
function clamp(value, hue) {
|
||||
return value < 0
|
||||
? 0
|
||||
: hue && value > 360
|
||||
? 360
|
||||
: !hue && value > 1
|
||||
? 1
|
||||
: value;
|
||||
}
|
||||
|
||||
var operators = {
|
||||
add: function(a, b, hue) {
|
||||
return clamp(a + b, hue);
|
||||
add: function(a, b) {
|
||||
return a + b;
|
||||
},
|
||||
|
||||
subtract: function(a, b, hue) {
|
||||
return clamp(a - b, hue);
|
||||
subtract: function(a, b) {
|
||||
return a - b;
|
||||
},
|
||||
|
||||
multiply: function(a, b, hue) {
|
||||
return clamp(a * b, hue);
|
||||
multiply: function(a, b) {
|
||||
return a * b;
|
||||
},
|
||||
|
||||
divide: function(a, b, hue) {
|
||||
return clamp(a / b, hue);
|
||||
divide: function(a, b) {
|
||||
return a / b;
|
||||
}
|
||||
};
|
||||
|
||||
return Base.each(operators, function(operator, name) {
|
||||
// Tell the argument reader not to parse values for multiply and divide,
|
||||
// so the are not clamped yet.
|
||||
var options = { dontParse: /^(multiply|divide)$/.test(name) };
|
||||
|
||||
this[name] = function(color) {
|
||||
color = Color.read(arguments, 0, 0, options);
|
||||
color = Color.read(arguments, 0, 0);
|
||||
var type = this._type,
|
||||
properties = this._properties,
|
||||
components1 = this._components,
|
||||
components2 = color._convert(type);
|
||||
for (var i = 0, l = components1.length; i < l; i++)
|
||||
components2[i] = operator(components1[i], components2[i],
|
||||
properties[i] === 'hue');
|
||||
components2[i] = operator(components1[i], components2[i]);
|
||||
return new Color(type, components2,
|
||||
this._alpha != null
|
||||
? operator(this._alpha, color.getAlpha())
|
||||
|
|
|
@ -51,6 +51,14 @@ test('Set color to array', function() {
|
|||
});
|
||||
|
||||
test('Creating Colors', function() {
|
||||
compareColors(new Color(), new Color(0, 0, 0),
|
||||
'Color with no arguments should be black');
|
||||
|
||||
compareColors(new Color('black'), new Color(0, 0, 0),
|
||||
'Color from name (black)');
|
||||
|
||||
compareColors(new Color('red'), new Color(1, 0, 0),
|
||||
'Color from name (red)');
|
||||
|
||||
compareColors(new Color('#ff0000'), new Color(1, 0, 0),
|
||||
'Color from hex code');
|
||||
|
@ -203,7 +211,7 @@ test('Saturation from black rgb', function() {
|
|||
test('Color#add', function() {
|
||||
var color = new Color(0, 1, 1);
|
||||
compareColors(color.add([1, 0, 0]), [1, 1, 1]);
|
||||
compareColors(color.add([1, 0.5, 0]), [1, 1, 1]);
|
||||
compareColors(color.add([1, 0.5, 0]), [1, 1.5, 1]);
|
||||
var color = new Color(0, 0.5, 0);
|
||||
compareColors(color.add(0.5), [0.5, 1, 0.5]);
|
||||
});
|
||||
|
@ -229,7 +237,7 @@ test('Color#divide', function() {
|
|||
var color = new Color(1, 1, 1);
|
||||
compareColors(color.divide([1, 2, 4]), [1, 0.5, 0.25]);
|
||||
var color = new Color(1, 0.5, 0.25);
|
||||
compareColors(color.divide(0.25), [1, 1, 1]);
|
||||
compareColors(color.divide(0.25), [4, 2, 1]);
|
||||
var color = new Color(1, 1, 1);
|
||||
compareColors(color.divide(4), [0.25, 0.25, 0.25]);
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@ test('PointText', function() {
|
|||
point: [100, 100],
|
||||
content: 'Hello World!'
|
||||
});
|
||||
equals(text.fillColor, { red: 0, green: 0, blue: 0 }, 'text.fillColor should be black by default');
|
||||
compareColors(text.fillColor, new Color(0, 0, 0), 'text.fillColor should be black by default');
|
||||
comparePoints(text.point, { x: 100, y: 100 });
|
||||
compareRectangles(text.bounds, { x: 100, y: 87.4, width: 77, height: 16.8 });
|
||||
equals(function() {
|
||||
|
|
Loading…
Reference in a new issue