More work on Color refactoring.

Improve backward compatible constructors.
This commit is contained in:
Jürg Lehni 2013-04-08 13:50:12 -07:00
parent 01673d675d
commit 062abab78b

View file

@ -210,37 +210,72 @@ var Color = this.Color = Base.extend(new function() {
converters[from + '-rgb'].apply(this, components)); converters[from + '-rgb'].apply(this, components));
} }
var fields = /** @lends Color# */{ // Produce getters and setter methods for the various color components known
// by the different color types. Requesting any of these components on any
// color internally converts the color to the required type and then returns
// its component.
return Base.each(types, function(properties, type) {
Base.each(properties, function(name, index) {
var isHue = name === 'hue',
// Both hue and saturation have overlapping properties between
// hsb and hsl. Handle this here separately, by testing for
// overlaps and skipping conversion if the type is /hs[bl]/
hasOverlap = /^(hue|saturation)$/.test(name),
part = Base.capitalize(name);
this['get' + part] = function() {
return this._type === type
|| hasOverlap && /^hs[bl]$/.test(this._type)
? this._components[index]
: convert(this._components, this._type, type)[index];
};
this['set' + part] = function(value) {
// Convert to the requrested type before setting the value
if (this._type !== type
&& !(hasOverlap && /^hs[bl]$/.test(this._type))) {
this._components = convert(this._components, this._type, type);
this._type = type;
}
this._components[index] = isHue
// Keep negative values within modulo 360 too:
? ((value % 360) + 360) % 360
// All other values are 0..1
: Math.min(Math.max(value, 0), 1);
};
}, this);
}, /** @lends Color# */{
_class: 'Color', _class: 'Color',
// Tell Base.read that we do not want null to be converted to a color. // Tell Base.read that we do not want null to be converted to a color.
_readNull: true, _readNull: true,
// Tell Base.read that the Point constructor supporst reading with index // Tell Base.read that the Point constructor supporst reading with index
_readIndex: true, _readIndex: true,
initialize: function(arg) { initialize: function(arg0, arg1) {
// We are storing color internally as an array of components // We are storing color internally as an array of components
var slice = Array.prototype.slice, var slice = Array.prototype.slice,
argType = arg != null && typeof arg, argType = arg0 != null && typeof arg0,
components = argType === 'number' components = argType === 'number'
? arguments ? arguments
: Array.isArray(arg) : Array.isArray(arg0)
? arg ? arg0
: null, : null,
read = 0, read = 0,
type, type,
alpha; alpha;
// Try type arg first // Try type arg0 first
if (argType === 'string' && arg in types) { if (argType === 'string' && arg0 in types) {
type = arg; type = arg0;
if (this._read) if (this._read)
read = 1; // will be increased below read = 1; // will be increased below
components = slice.call(arguments, 1); components = typeof arg1 === 'number'
? slice.call(arguments, 1) : arg1;
} }
if (components) { if (components) {
if (!type) if (!type)
// type = arg.length >= 4 // type = components.length >= 4
// ? 'cmyk' // ? 'cmyk'
// : arg.length >= 3 // : components.length >= 3
type = components.length >= 3 type = components.length >= 3
? 'rgb' ? 'rgb'
: 'gray'; : 'gray';
@ -254,31 +289,31 @@ var Color = this.Color = Base.extend(new function() {
} else { } else {
if (argType === 'string') { if (argType === 'string') {
type = 'rgb'; type = 'rgb';
components = arg.match(/^#[0-9a-f]{3,6}$/i) components = arg0.match(/^#[0-9a-f]{3,6}$/i)
? hexToRgb(arg) ? hexToRgb(arg0)
: nameToRgb(arg); : nameToRgb(arg0);
} else if (argType === 'object') { } else if (argType === 'object') {
if (arg._class === 'Color') { if (arg0._class === 'Color') {
type = arg._type; type = arg0._type;
components = arg._components.slice(); components = arg0._components.slice();
alpha = arg._alpha; alpha = arg0._alpha;
} else if (arg._class === 'Gradient') { } else if (arg0._class === 'Gradient') {
// TODO: Construct gradient // TODO: Construct gradient
type = 'gradient'; type = 'gradient';
} else { } else {
// Determine type by presence of object property names // Determine type by presence of object property names
type = 'hue' in arg type = 'hue' in arg0
? 'lightness' in arg ? 'lightness' in arg0
? 'hsl' ? 'hsl'
: 'hsb' : 'hsb'
: 'gray' in arg : 'gray' in arg0
? 'gray' ? 'gray'
: 'rgb'; : 'rgb';
var properties = types[type]; var properties = types[type];
components = []; components = [];
for (var i = 0, l = properties.length; i < l; i++) for (var i = 0, l = properties.length; i < l; i++)
components[i] = arg[properties[i]] || 0; components[i] = arg0[properties[i]] || 0;
alpha = arg.alpha; alpha = arg0.alpha;
} }
} }
if (this._read && type) if (this._read && type)
@ -567,6 +602,9 @@ var Color = this.Color = Base.extend(new function() {
*/ */
statics: /** @lends Color */{ statics: /** @lends Color */{
// Export for backward compatibility code below.
_types: types,
create: function(type, components, alpha) { create: function(type, components, alpha) {
var color = Base.create(Color); var color = Base.create(Color);
color._type = type; color._type = type;
@ -580,63 +618,19 @@ var Color = this.Color = Base.extend(new function() {
return new Color(random(), random(), random()); return new Color(random(), random(), random());
} }
} }
}; });
// Produce getters and setter methods for the various color components known
// by the different color types. Requesting any of these components on any
// color internally converts the color to the required type and then returns
// its component.
return Base.each(types, function(properties, type) {
Base.each(properties, function(name, index) {
var isHue = name === 'hue',
// Both hue and saturation have overlapping properties between
// hsb and hsl. Handle this here separately, by testing for
// overlaps and skipping conversion if the type is /hs[bl]/
hasOverlap = /^(hue|saturation)$/.test(name),
part = Base.capitalize(name);
this['get' + part] = function() {
return this._type === type
|| hasOverlap && /^hs[bl]$/.test(this._type)
? this._components[index]
: convert(this._components, this._type, type)[index];
};
this['set' + part] = function(value) {
// Convert to the requrested type before setting the value
if (this._type !== type
&& !(hasOverlap && /^hs[bl]$/.test(this._type))) {
this._components = convert(this._components, this._type, type);
this._type = type;
}
this._components[index] = isHue
// Keep negative values within modulo 360 too:
? ((value % 360) + 360) % 360
// All other values are 0..1
: Math.min(Math.max(value, 0), 1);
};
}, this);
}, fields);
}); });
// TODO: Consider producing these in a loop instead, accessing the private Base.each(Color._types, function(properties, type) {
// components data somehow. this[Base.capitalize(type) + 'Color'] = this[type.toUpperCase() + 'Color'] =
function(arg) {
// RGBColor references RgbColor inside PaperScopes for backward compatibility var components = typeof arg === 'number'
var RgbColor = this.RgbColor = this.RGBColor = function(red, green, blue, alpha) { ? arguments
return new Color(red, green, blue, alpha); : Array.isArray(arg)
}; ? arg
: null;
var GrayColor = this.GrayColor = function(gray, alpha) { return components
return new Color({ gray: gray, alpha: alpha }); ? new Color(type, components)
}; : new Color(arg);
};
// HSBColor references HsbColor inside PaperScopes for backward compatibility }, this);
var HsbColor = this.HsbColor = this.HSBColor = function(hue, saturation, brightness, alpha) {
return new Color({ hue: hue, saturation: saturation, brightness: brightness });
};
// HSLColor references HslColor inside PaperScopes for backward compatibility
var HslColor = this.HslColor = this.HSLColor = function(hue, saturation, lightness, alpha) {
return new Color({ hue: hue, saturation: saturation, lightness: lightness });
};