mirror of
https://github.com/PitPik/colorPicker.git
synced 2025-07-15 22:14:29 -06:00
Using ColorPicker.prototype.saveAsBackground needs some update of variables (in preRenderAll()) to render the WGCA bar right and calculating all color values correct…
1338 lines
48 KiB
JavaScript
1338 lines
48 KiB
JavaScript
;(function(window, undefined){
|
||
"use strict"
|
||
|
||
var _data = window.ColorPicker, // will be deleted in buildView() and holds:
|
||
// window.ColorPicker = { // comes from colorPicker.data.js and will be overwritten.
|
||
// _html: ..., // holds the HTML markup of colorPicker
|
||
// _cssFunc: ..., // CSS for all the sliders
|
||
// _cssMain: ..., // CSS of the GUI
|
||
// _horizontalPng: ..., // horizontal background images for sliders
|
||
// _verticalPng: ..., // vertical background images for sliders
|
||
// _patchesPng: ..., // background images for square sliders in RGB mode
|
||
// _iconsPng: ..., // some icon sprite images
|
||
// _bgsPng: ..., // some more icon sprite images
|
||
// _blankPng: ... // the blank 16x16px image for the transparent cursor
|
||
// }
|
||
_devMode = !_data, // if no _data we assume that colorPicker.data.js is missing (for development)
|
||
_isIE = document.createStyleSheet !== undefined && document.getElementById,
|
||
// _isIE8 = _isIE && document.querySelectorAll,
|
||
|
||
_valueRanges = {}, // will be assigned in initInstance() by Colors instance
|
||
// _valueRanges = {
|
||
// rgb: {r: [0, 255], g: [0, 255], b: [0, 255]},
|
||
// hsv: {h: [0, 360], s: [0, 100], v: [0, 100]},
|
||
// hsl: {h: [0, 360], s: [0, 100], l: [0, 100]},
|
||
// cmyk: {c: [0, 100], m: [0, 100], y: [0, 100], k: [0, 100]},
|
||
// cmy: {c: [0, 100], m: [0, 100], y: [0, 100]},
|
||
// XYZ: {X: [0, 100], Y: [0, 100], Z: [0, 100]},
|
||
// Lab: {L: [0, 100], a: [-128, 127], b: [-128, 127]},
|
||
// alpha: {alpha: [0, 1]},
|
||
// HEX: {HEX: [0, 16777215]}
|
||
// },
|
||
_bgTypes = {w: 'White', b: 'Black', c: 'Custom'},
|
||
|
||
_mouseMoveAction, // current mouseMove handler assigned on mouseDown
|
||
_mainTarget, // target on mouseDown, might be parent element though...
|
||
_valueType, // check this variable; gets missused/polutet over time
|
||
_delayState = 1, // mouseMove offset (y-axis) in display elements // same here...
|
||
_startCoords = {},
|
||
_targetOrigin = {},
|
||
_renderTimer, // animationFrame/interval variable
|
||
_newData = true,
|
||
// _txt = {
|
||
// selection: document.selection || window.getSelection(),
|
||
// range: (document.createRange ? document.createRange() : document.body.createTextRange())
|
||
// },
|
||
|
||
_renderVars = {}, // used only in renderAll and convertColors
|
||
_cashedVars = {}, // reset in initSliders
|
||
|
||
_colorPicker,
|
||
_previousInstance, // only used for recycling purposes in buildView()
|
||
_colorInstance = {},
|
||
_colors = {},
|
||
_options = {},
|
||
_nodes = {},
|
||
|
||
animationFrame = 'AnimationFrame', // we also need this later
|
||
requestAnimationFrame = 'request' + animationFrame,
|
||
cancelAnimationFrame = 'cancel' + animationFrame,
|
||
vendors = ['ms', 'moz', 'webkit', 'o'],
|
||
|
||
ColorPicker = function(options) { // as tiny as possible...
|
||
this.options = {
|
||
color: 'rgba(204, 82, 37, 0.8)',
|
||
mode: 'rgb-b',
|
||
fps: 60, // 1000 / 60 = ~16.7ms
|
||
delayOffset: 8,
|
||
CSSPrefix: 'cp-',
|
||
allMixDetails: true,
|
||
alphaBG: 'w',
|
||
imagePath: ''
|
||
// devPicker: false // uses existing HTML for development...
|
||
// noAlpha: true,
|
||
// customBG: '#808080'
|
||
// size: 0,
|
||
// cmyOnly: false,
|
||
// initStyle: 'display: none',
|
||
|
||
// memoryColors: [{r: 100, g: 200, b: 10}]// , a: 0.5
|
||
|
||
// opacityPositionRelative: undefined,
|
||
// customCSS: undefined,
|
||
// appenTo: document.body,
|
||
// noRangeBackground: false,
|
||
// textRight: false, ?????
|
||
// noHexButton: false,
|
||
// noResize: false,
|
||
|
||
// noRGBr: false,
|
||
// noRGBg: false,
|
||
// noRGBb: false,
|
||
|
||
// ------ CSSStrength: 'div.',
|
||
// XYZMatrix: XYZMatrix,
|
||
// XYZReference: {},
|
||
// grey: grey,
|
||
// luminance: luminance,
|
||
|
||
// renderCallback: undefined,
|
||
// actionCallback: undefined,
|
||
// convertCallback: undefined,
|
||
};
|
||
initInstance(this, options || {});
|
||
};
|
||
|
||
window.ColorPicker = ColorPicker; // export differently
|
||
ColorPicker.addEvent = addEvent;
|
||
ColorPicker.removeEvent = removeEvent;
|
||
ColorPicker.getOrigin = getOrigin;
|
||
ColorPicker.limitValue = limitValue;
|
||
ColorPicker.changeClass = changeClass;
|
||
|
||
// ------------------------------------------------------ //
|
||
|
||
ColorPicker.prototype.setColor = function(newCol, type, alpha, forceRender) {
|
||
focusInstance(this);
|
||
_valueType = true; // right cursor...
|
||
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers
|
||
preRenderAll(_colorInstance.setColor.apply(_colorInstance, arguments));
|
||
if (forceRender) {
|
||
this.startRender(true);
|
||
}
|
||
};
|
||
|
||
ColorPicker.prototype.saveAsBackground = function() {
|
||
focusInstance(this);
|
||
return saveAsBackground(true);
|
||
};
|
||
|
||
ColorPicker.prototype.setCustomBackground = function(col) {
|
||
focusInstance(this); // needed???
|
||
return _colorInstance.setCustomBackground(col);
|
||
};
|
||
|
||
ColorPicker.prototype.startRender = function(oneTime) {
|
||
focusInstance(this);
|
||
if (oneTime) {
|
||
_mouseMoveAction = false; // prevents window[requestAnimationFrame] in renderAll()
|
||
renderAll();
|
||
this.stopRender();
|
||
} else {
|
||
_mouseMoveAction = 1;
|
||
_renderTimer = window[requestAnimationFrame](renderAll);
|
||
}
|
||
};
|
||
|
||
ColorPicker.prototype.stopRender = function() {
|
||
focusInstance(this); // check again
|
||
window[cancelAnimationFrame](_renderTimer);
|
||
if (_valueType) {
|
||
// renderAll();
|
||
_mouseMoveAction = 1;
|
||
stopChange(undefined, 'external');
|
||
// _valueType = undefined;
|
||
}
|
||
};
|
||
|
||
ColorPicker.prototype.setMode = function(mode) { // check again ... right cursor
|
||
focusInstance(this);
|
||
setMode(mode);
|
||
initSliders();
|
||
renderAll();
|
||
};
|
||
|
||
ColorPicker.prototype.destroyAll = function() { // check this again...
|
||
var html = this.nodes.colorPicker,
|
||
destroyReferences = function(nodes) {
|
||
for (var n in nodes) {
|
||
if (nodes[n] && nodes[n].toString() === '[object Object]' || nodes[n] instanceof Array) {
|
||
destroyReferences(nodes[n]);
|
||
}
|
||
nodes[n] = null;
|
||
delete nodes[n];
|
||
}
|
||
};
|
||
|
||
this.stopRender();
|
||
installEventListeners(this, true);
|
||
destroyReferences(this);
|
||
html.parentNode.removeChild(html);
|
||
html = null;
|
||
};
|
||
|
||
// ------------------------------------------------------ //
|
||
|
||
function initInstance(THIS, options) {
|
||
var exporter, // do something here..
|
||
memory,
|
||
mode = '',
|
||
CSSPrefix = '',
|
||
optionButtons;
|
||
|
||
for (var option in options) { // deep copy ??
|
||
THIS.options[option] = options[option];
|
||
}
|
||
_colorInstance = new Colors(THIS.options);
|
||
// We transfer the responsibility to the instance of Color (to save space and memory)
|
||
delete THIS.options;
|
||
_options = _colorInstance.options;
|
||
_options.scale = 1;
|
||
CSSPrefix = _options.CSSPrefix;
|
||
|
||
THIS.color = _colorInstance; // check this again...
|
||
_valueRanges = _options.valueRanges;
|
||
THIS.nodes = _nodes = getInstanceNodes(buildView(THIS), THIS); // ha, ha,... make this different
|
||
setMode(_options.mode);
|
||
focusInstance(THIS);
|
||
saveAsBackground();
|
||
|
||
mode = ' ' + _options.mode.type + '-' + _options.mode.z;
|
||
_nodes.slds.className += mode;
|
||
_nodes.panel.className += mode;
|
||
//_nodes.colorPicker.className += ' cmy-' + _options.cmyOnly;
|
||
|
||
if (_options.noHexButton) {
|
||
changeClass(_nodes.HEX_butt, CSSPrefix + 'butt', CSSPrefix + 'labl');
|
||
}
|
||
|
||
if (_options.size !== undefined) {
|
||
resizeApp(undefined, _options.size);
|
||
}
|
||
|
||
optionButtons = {
|
||
alphaBG: _nodes.alpha_labl,
|
||
cmyOnly: _nodes.HEX_labl // test... take out
|
||
};
|
||
for (var n in optionButtons) {
|
||
if (_options[n] !== undefined) {
|
||
buttonActions({target: optionButtons[n], data: _options[n]});
|
||
}
|
||
}
|
||
if (_options.noAlpha) {
|
||
_nodes.colorPicker.className += ' no-alpha'; // IE6 ??? maybe for IE6 on document.body
|
||
}
|
||
|
||
memory = _options.memoryColors;
|
||
for (var n = _nodes.memos.length; n--; ) { // check again how to handle alpha...
|
||
_nodes.memos[n].style.cssText = 'background-color: ' + (memory && memory[n] !== undefined ?
|
||
color2string(memory[n]) + ';' + getOpacityCSS(memory[n]['a'] || 1) : 'rgb(0,0,0);');
|
||
}
|
||
|
||
installEventListeners(THIS);
|
||
|
||
_mouseMoveAction = true;
|
||
stopChange(undefined, 'init');
|
||
|
||
if (_previousInstance) {
|
||
focusInstance(_previousInstance);
|
||
renderAll();
|
||
}
|
||
}
|
||
|
||
function focusInstance(THIS) {
|
||
_newData = true;
|
||
if (_colorPicker !== THIS) {
|
||
_colorPicker = THIS;
|
||
_colors = THIS.color.colors;
|
||
_options = THIS.color.options;
|
||
_nodes = THIS.nodes;
|
||
_colorInstance = THIS.color;
|
||
|
||
_cashedVars = {};
|
||
preRenderAll(_colors);
|
||
}
|
||
}
|
||
|
||
function getUISizes() {
|
||
var sizes = ['L', 'S', 'XS', 'XXS'];
|
||
_options.sizes = {};
|
||
_nodes.testNode.style.cssText = 'position:absolute;left:-1000px;top:-1000px;';
|
||
document.body.appendChild(_nodes.testNode);
|
||
for (var n = sizes.length; n--; ) {
|
||
_nodes.testNode.className = _options.CSSPrefix + 'app ' + sizes[n];
|
||
_options.sizes[sizes[n]] = [_nodes.testNode.offsetWidth, _nodes.testNode.offsetHeight];
|
||
}
|
||
if (_nodes.testNode.removeNode) { // old IEs
|
||
_nodes.testNode.removeNode(true);
|
||
} else {
|
||
document.body.removeChild(_nodes.testNode);
|
||
}
|
||
}
|
||
|
||
function buildView(THIS) {
|
||
var app = document.createElement('div'),
|
||
prefix = _options.CSSPrefix,
|
||
urlData = 'data:image/png;base64,',
|
||
addStyleSheet = function(cssText, id) {
|
||
var style = document.createElement('style');
|
||
|
||
style.setAttribute('type', 'text/css');
|
||
if (id) {
|
||
style.setAttribute('id', id);
|
||
}
|
||
if (!style.styleSheet) {
|
||
style.appendChild(document.createTextNode(cssText));
|
||
}
|
||
document.getElementsByTagName('head')[0].appendChild(style);
|
||
if (style.styleSheet) { // IE compatible
|
||
document.styleSheets[document.styleSheets.length-1].cssText = cssText;
|
||
}
|
||
};
|
||
|
||
// development mode
|
||
if (_devMode) {
|
||
return THIS.color.options.devPicker;
|
||
}
|
||
|
||
// HTML
|
||
if (_previousInstance = _colorPicker) {
|
||
// we need to be careful with recycling HTML as slider calssNames might have been changed...
|
||
initSliders();
|
||
}
|
||
app.innerHTML = _colorPicker ? _colorPicker.nodes.colorPicker.outerHTML : _data._html.replace(/§/g, prefix);
|
||
// _html = null;
|
||
|
||
// CSS
|
||
if (!document.getElementById('colorPickerCSS')) { // only once needed
|
||
// CSS - system
|
||
_data._cssFunc = _data._cssFunc.
|
||
replace(/§/g, prefix).
|
||
replace('_patches.png', !_isIE ? urlData + _data._patchesPng : _options.imagePath + '_patches.png').
|
||
replace('_vertical.png', !_isIE ? urlData + _data._verticalPng : _options.imagePath + '_vertical.png').
|
||
replace('_horizontal.png', !_isIE ? urlData + _data._horizontalPng :
|
||
_options.imagePath + '_horizontal.png');
|
||
addStyleSheet(_data._cssFunc, 'colorPickerCSS');
|
||
// CSS - main
|
||
if (!_options.customCSS) {
|
||
_data._cssMain = _data._cssMain.
|
||
replace(/§/g, prefix).
|
||
replace('_bgs.png', !_isIE ? urlData + _data._bgsPng : _options.imagePath + '_bgs.png').
|
||
replace('_icons.png', !_isIE ? urlData + _data._iconsPng : _options.imagePath + '_icons.png').
|
||
replace('_blank.png', !_isIE ? urlData + _data._blankPng : _options.imagePath + '_blank.cur').
|
||
replace('"Courier New",', !_isIE ? '' : '"Courier New",').
|
||
replace(/opacity:(\d*\.*(\d+))/g, function($1, $2){
|
||
return _isIE ? '-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=' +
|
||
Math.round(+$2 * 100) + ')";filter: alpha(opacity=' + Math.round(+$2 * 100) + ')' :
|
||
'-moz-opacity: ' + $2 + '; -khtml-opacity: ' + $2 + '; opacity: ' + $2;
|
||
});
|
||
// style.appendChild(document.createTextNode(_data._cssFunc));
|
||
addStyleSheet(_data._cssMain);
|
||
}
|
||
for (var n in _data) { // almost 25k of memory ;o)
|
||
_data[n] = null;
|
||
}
|
||
}
|
||
|
||
app.children[0].style.cssText = _options.initStyle || ''; // for initial hiding...
|
||
|
||
return (_options.appenTo || document.body).appendChild(app.children[0]);
|
||
}
|
||
|
||
function getInstanceNodes(colorPicker, THIS) { // check nodes again... are they all needed?
|
||
var all = colorPicker.getElementsByTagName('*'),
|
||
nodes = {colorPicker: colorPicker}, // length ?? // rename nodes.colorPicker
|
||
node,
|
||
className,
|
||
memoCounter = 0,
|
||
regexp = new RegExp(_options.CSSPrefix);
|
||
|
||
// nodes.displayStyles = {}; // not needed ... or change to CSS
|
||
nodes.styles = {};
|
||
// nodes.styles.displays = {};
|
||
|
||
nodes.textNodes = {};
|
||
nodes.memos = [];
|
||
nodes.testNode = document.createElement('div');
|
||
|
||
for (var n = 0, m = all.length; n < m; n++) {
|
||
node = all[n];
|
||
if ((className = node.className) && regexp.test(className)) {
|
||
className = className.split(' ')[0].replace(_options.CSSPrefix, '').replace(/-/g, '_');
|
||
if (/_disp/.test(className)) {
|
||
className = className.replace('_disp', '');
|
||
// nodes.styles.displays[className] = node.style;
|
||
nodes.styles[className] = node.style;
|
||
nodes.textNodes[className] = node.firstChild;
|
||
node.contentEditable = true; // does this slow down rendering??
|
||
} else {
|
||
if (!(/(?:hs|cmyk|Lab).*?(?:butt|labl)/.test(className))) {
|
||
nodes[className] = node;
|
||
}
|
||
if (/(?:cur|sld[^s]|opacity|cont|col)/.test(className)) {
|
||
nodes.styles[className] = /(?:col\d)/.test(className) ? node.children[0].style : node.style;
|
||
}
|
||
}
|
||
} else if (/memo/.test(node.parentNode.className)) {
|
||
nodes.memos.push(node);
|
||
}
|
||
}
|
||
|
||
return nodes;
|
||
}
|
||
|
||
// ------------------------------------------------------ //
|
||
// ---- Add event listners to colorPicker and window ---- //
|
||
// -------------------------------------------------------//
|
||
|
||
function installEventListeners(THIS, off) {
|
||
var onOffEvent = off ? removeEvent : addEvent;
|
||
|
||
onOffEvent(_nodes.colorPicker, 'mousedown', function(e) {
|
||
var event = e || window.event,
|
||
page = getPageXY(event),
|
||
target = event.target || event.srcElement,
|
||
className = target.className;
|
||
|
||
focusInstance(THIS);
|
||
_mainTarget = target;
|
||
stopChange(undefined, 'resetEventListener');
|
||
|
||
if (target === _nodes.sldl_3 || target === _nodes.curm) {
|
||
_mainTarget = _nodes.sldl_3;
|
||
_mouseMoveAction = changeXYValue;
|
||
changeClass(_nodes.slds, 'do-drag');
|
||
} else if (/sldr/.test(className) || target === _nodes.curl || target === _nodes.curr) {
|
||
_mainTarget = _nodes.sldr_4;
|
||
_mouseMoveAction = changeZValue;
|
||
} else if (target === _nodes.opacity.children[0] || target === _nodes.opacity_slider) {
|
||
_mainTarget = _nodes.opacity;
|
||
_mouseMoveAction = changeOpacityValue;
|
||
} else if (/-disp/.test(className) && !/HEX-/.test(className)) {
|
||
_mouseMoveAction = changeInputValue;
|
||
(target.nextSibling.nodeType === 3 ? target.nextSibling.nextSibling : target.nextSibling).
|
||
appendChild(_nodes.nsarrow); // nextSibling for better text selection
|
||
_valueType = className.split('-disp')[0].split('-');
|
||
_valueType = {type: _valueType[0], z: _valueType[1] || ''};
|
||
changeClass(_nodes.panel, 'start-change');
|
||
_delayState = 0;
|
||
} else if (target === _nodes.resize && !_options.noResize) {
|
||
if (!_options.sizes) {
|
||
getUISizes();
|
||
}
|
||
_mainTarget = _nodes.resizer;
|
||
_mouseMoveAction = resizeApp;
|
||
} else {
|
||
_mouseMoveAction = undefined;
|
||
}
|
||
|
||
if (_mouseMoveAction) {
|
||
_startCoords = {pageX: page.X, pageY: page.Y};
|
||
_mainTarget.style.display = 'block'; // for resizer...
|
||
_targetOrigin = getOrigin(_mainTarget);
|
||
_targetOrigin.width = _nodes.opacity.offsetWidth; // ???????
|
||
_targetOrigin.childWidth = _nodes.opacity_slider.offsetWidth; // ???????
|
||
_mainTarget.style.display = ''; // ??? for resizer...
|
||
_mouseMoveAction(event);
|
||
addEvent(_isIE ? document.body : window, 'mousemove', _mouseMoveAction);
|
||
_renderTimer = window[requestAnimationFrame](renderAll);
|
||
} else {
|
||
// console.log(className)
|
||
// console.log(THIS.nodes[className.split(' ')[0].replace('cp-', '').replace('-', '_')])
|
||
// resize, button states, etc...
|
||
}
|
||
|
||
// if (_mouseMoveAction !== changeInputValue) preventDefault(event);
|
||
if (!/-disp/.test(className)) {
|
||
return preventDefault(event);
|
||
// document.activeElement.blur();
|
||
}
|
||
});
|
||
|
||
onOffEvent(_nodes.colorPicker, 'click', function(e) {
|
||
focusInstance(THIS);
|
||
buttonActions(e);
|
||
});
|
||
|
||
onOffEvent(_nodes.colorPicker, 'dblclick', buttonActions);
|
||
|
||
onOffEvent(_nodes.colorPicker, 'keydown', function(e) {
|
||
focusInstance(THIS);
|
||
keyControl(e);
|
||
});
|
||
|
||
// keydown is before keypress and focuses already
|
||
onOffEvent(_nodes.colorPicker, 'keypress', keyControl);
|
||
// onOffEvent(_nodes.colorPicker, 'keyup', keyControl);
|
||
|
||
onOffEvent(_nodes.colorPicker, 'paste', function(e) {
|
||
e.target.firstChild.data = e.clipboardData.getData('Text');
|
||
return preventDefault(e);
|
||
});
|
||
}
|
||
|
||
addEvent(_isIE ? document.body : window, 'mouseup', stopChange);
|
||
|
||
// ------------------------------------------------------ //
|
||
// --------- Event listner's callback functions -------- //
|
||
// -------------------------------------------------------//
|
||
|
||
function stopChange(e, action) {
|
||
var mouseMoveAction = _mouseMoveAction;
|
||
|
||
if (_mouseMoveAction) { // why??? please test again...
|
||
// if (document.selection && _mouseMoveAction !== changeInputValue) {
|
||
// //ie -> prevent showing the accelerator menu
|
||
// document.selection.empty();
|
||
// }
|
||
window[cancelAnimationFrame](_renderTimer);
|
||
removeEvent(_isIE ? document.body : window, 'mousemove', _mouseMoveAction);
|
||
if (_delayState) { // hapens on inputs
|
||
_valueType = {type: 'alpha'};
|
||
renderAll();
|
||
}
|
||
// this is dirty... has to do with M|W|! button
|
||
if (typeof _mouseMoveAction === 'function' || typeof _mouseMoveAction === 'number') {
|
||
delete _options.webUnsave;
|
||
}
|
||
|
||
_delayState = 1;
|
||
_mouseMoveAction = undefined;
|
||
|
||
changeClass(_nodes.slds, 'do-drag', '');
|
||
changeClass(_nodes.panel, '(?:start-change|do-change)', '');
|
||
|
||
_nodes.resizer.style.cssText = '';
|
||
|
||
_nodes.memo_store.style.cssText = 'background-color: ' +
|
||
color2string(_colors.RND.rgb) + '; ' + getOpacityCSS(_colors.alpha);
|
||
_nodes.memo.className = _nodes.memo.className.replace(/\s+(?:dark|light)/, '') +
|
||
// (/dark/.test(_nodes.colorPicker.className) ? ' dark' : ' light');
|
||
(_colors['rgbaMix' + _bgTypes[_options.alphaBG]].luminance < 0.22 ? ' dark' : ' light');
|
||
// (_colors.rgbaMixCustom.luminance < 0.22 ? ' dark' : ' light')
|
||
|
||
_valueType = undefined;
|
||
|
||
resetCursors();
|
||
|
||
if (_options.actionCallback) {
|
||
_options.actionCallback(e, mouseMoveAction.name || action || 'external');
|
||
}
|
||
}
|
||
}
|
||
|
||
function changeXYValue(e) {
|
||
var event = e || window.event,
|
||
scale = _options.scale,
|
||
page = getPageXY(event),
|
||
x = (page.X - _targetOrigin.left) * (scale === 4 ? 2 : scale),
|
||
y = (page.Y - _targetOrigin.top) * scale,
|
||
mode = _options.mode;
|
||
|
||
_colors[mode.type][mode.x] = limitValue(x / 255, 0, 1);
|
||
_colors[mode.type][mode.y] = 1 - limitValue(y / 255, 0, 1);
|
||
convertColors();
|
||
return preventDefault(event);
|
||
}
|
||
|
||
function changeZValue(e) { // make this part of changeXYValue
|
||
var event = e || window.event,
|
||
page = getPageXY(event),
|
||
z = (page.Y - _targetOrigin.top) * _options.scale,
|
||
mode = _options.mode;
|
||
|
||
_colors[mode.type][mode.z] = 1 - limitValue(z / 255, 0, 1);
|
||
convertColors();
|
||
return preventDefault(event);
|
||
}
|
||
|
||
function changeOpacityValue(e) {
|
||
var event = e || window.event,
|
||
page = getPageXY(event);
|
||
|
||
_newData = true;
|
||
_colors.alpha = limitValue(Math.round(
|
||
(page.X - _targetOrigin.left) / _targetOrigin.width * 100), 0, 100
|
||
) / 100;
|
||
convertColors('alpha');
|
||
return preventDefault(event);
|
||
}
|
||
|
||
function changeInputValue(e) {
|
||
var event = e || window.event,
|
||
page = getPageXY(event),
|
||
delta = _startCoords.pageY - page.Y,
|
||
delayOffset = _options.delayOffset,
|
||
type = _valueType.type,
|
||
isAlpha = type === 'alpha',
|
||
ranges;
|
||
|
||
if (_delayState || Math.abs(delta) >= delayOffset) {
|
||
if (!_delayState) {
|
||
_delayState = (delta > 0 ? -delayOffset : delayOffset) +
|
||
(+_mainTarget.firstChild.data) * (isAlpha ? 100 : 1);
|
||
_startCoords.pageY += _delayState;
|
||
delta += _delayState;
|
||
_delayState = 1;
|
||
changeClass(_nodes.panel, 'start-change', 'do-change');
|
||
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
|
||
document.activeElement.blur();
|
||
_renderTimer = window[requestAnimationFrame](renderAll);
|
||
}
|
||
|
||
if (type === 'cmyk' && _options.cmyOnly) {
|
||
type = 'cmy';
|
||
}
|
||
|
||
if (isAlpha) {
|
||
_newData = true;
|
||
_colors.alpha = limitValue(delta / 100, 0, 1);
|
||
} else {
|
||
ranges = _valueRanges[type][_valueType.z];
|
||
_colors[type][_valueType.z] = type === 'Lab' ? limitValue(delta, ranges[0], ranges[1]) :
|
||
limitValue(delta / ranges[1], 0, 1);
|
||
}
|
||
convertColors(isAlpha ? 'alpha' : type);
|
||
// event.returnValue is deprecated. Please use the standard event.preventDefault() instead.
|
||
// event.returnValue = false; // see: pauseEvent(event);
|
||
return preventDefault(event);
|
||
}
|
||
}
|
||
|
||
function keyControl(e) { // this is quite big for what it does...
|
||
var event = e || window.event,
|
||
keyCode = event.which || event.keyCode,
|
||
key = String.fromCharCode(keyCode),
|
||
elm = document.activeElement,
|
||
|
||
cln = elm.className.replace(_options.CSSPrefix, '').split('-'),
|
||
type = cln[0],
|
||
mode = cln[1],
|
||
|
||
isAlpha = type === 'alpha',
|
||
isHex = type === 'HEX',
|
||
arrowKey = {k40: -1, k38: 1, k34: -10, k33: 10}['k' + keyCode] / (isAlpha ? 100 : 1),
|
||
validKeys = {'HEX': /[0-9a-fA-F]/, 'Lab': /[\-0-9]/, 'alpha': /[\.0-9]/}[type] || /[0-9]/,
|
||
valueRange = _valueRanges[type][type] || _valueRanges[type][mode], // let op!
|
||
|
||
textNode = elm.firstChild, // chnge on TAB key
|
||
rangeData = caret(elm),
|
||
origValue = textNode.data, // do not change
|
||
value,
|
||
val = origValue === '0' && !isHex ? [] : origValue.split(''); // gefixt
|
||
|
||
if (/^(?:27|13)$/.test(keyCode)) { // ENTER || ESC
|
||
// preventDefault(event);
|
||
elm.blur();
|
||
} else if (event.type === 'keydown') { // functional keys
|
||
if (arrowKey) { // arrow/page keys
|
||
value = limitValue(Math.round((+origValue + arrowKey) * 1e+6) / 1e+6, valueRange[0], valueRange[1]);
|
||
} else if (/^(?:8|46)$/.test(keyCode)) { // DELETE / BACKSPACE
|
||
if (!rangeData.range) {
|
||
rangeData.range++;
|
||
rangeData.start -= keyCode === 8 ? 1 : 0;
|
||
}
|
||
val.splice(rangeData.start, rangeData.range);
|
||
value = val.join('') || '0'; // never loose elm.firstChild
|
||
}
|
||
|
||
if (value !== undefined) { // prevent keypress
|
||
preventDefault(event, true);
|
||
}
|
||
} else if (event.type === 'keypress') {
|
||
if (!/^(?:37|39|8|46|9)$/.test(keyCode)) { // left, right,DEL, BACK, TAB for FF
|
||
preventDefault(event, true);
|
||
}
|
||
if (validKeys.test(key)) { // regular input
|
||
val.splice(rangeData.start, rangeData.range, key);
|
||
value = val.join('');
|
||
}
|
||
rangeData.start++;
|
||
}
|
||
|
||
if (keyCode === 13 && isHex) {
|
||
if (textNode.data.length % 3 === 0 || textNode.data === '0') { // textNode.data.length &&
|
||
return _colorPicker.setColor(textNode.data === '0' ? '000' : textNode.data, 'rgb', _colors.alpha, true);
|
||
} else {
|
||
preventDefault(event, true);
|
||
return elm.focus();
|
||
}
|
||
}
|
||
|
||
if (isHex && value !== undefined) {
|
||
value = /^0+/.test(value) ? value : parseInt(''+value, 16) || 0;
|
||
}
|
||
|
||
if (value !== undefined && value !== '' && +value >= valueRange[0] && +value <= valueRange[1]) {
|
||
if (isHex) {
|
||
value = value.toString(16).toUpperCase() || '0';
|
||
}
|
||
if (isAlpha) {
|
||
_colors[type] = +value;
|
||
} else if (!isHex) {
|
||
_colors[type][mode] = +value / (type === 'Lab' ? 1 : valueRange[1]);
|
||
}
|
||
convertColors(isAlpha ? 'alpha' : type);
|
||
|
||
preRenderAll(_colors);
|
||
_mouseMoveAction = true;
|
||
stopChange(e, event.type);
|
||
|
||
textNode.data = value; // if
|
||
caret(elm, Math.min(elm.firstChild.data.length, rangeData.start < 0 ? 0 : rangeData.start));
|
||
}
|
||
}
|
||
|
||
function buttonActions(e) {
|
||
var event = e || window.event,
|
||
target = event.target || event.srcElement,
|
||
targetClass = target.className,
|
||
parent = target.parentNode,
|
||
options = _options,
|
||
RGB = _colors.RND.rgb,
|
||
customBG, alphaBG,
|
||
mode = _options.mode,
|
||
newMode = '',
|
||
prefix = options.CSSPrefix,
|
||
isModeButton = /(?:hs|rgb)/.test(parent.className) && /^[HSBLRG]$/.test(
|
||
target.firstChild ? target.firstChild.data : ''
|
||
),
|
||
isDblClick = /dblc/.test(event.type),
|
||
buttonAction = ''; // think this over again....
|
||
|
||
if (isDblClick && !isModeButton) {
|
||
return;
|
||
} else if (targetClass.indexOf('-labl ' + prefix + 'labl') !== -1) { // HSB -> HSL; CMYK -> Lab buttons
|
||
changeClass(_nodes[targetClass.split('-')[0]], prefix + 'hide', '');
|
||
changeClass(_nodes[parent.className.split('-')[1]], prefix + 'hide');
|
||
} else if (targetClass.indexOf(prefix + 'butt') !== -1) { // BUTTONS
|
||
if (isModeButton) { // set render modes
|
||
if (isDblClick && _options.scale === 2) {
|
||
newMode = /hs/.test(mode.type) ? 'rgb' : /hide/.test(_nodes.hsl.className) ? 'hsv' : 'hsl';
|
||
newMode = newMode + '-' + newMode[mode.type.indexOf(mode.z)];
|
||
}
|
||
_colorPicker.setMode(newMode ? newMode : targetClass.replace('-butt', '').split(' ')[0]);
|
||
buttonAction = 'modeChange';
|
||
} else if (/^[rgb]/.test(targetClass)) { // no vertical slider rendering in RGB mode
|
||
newMode = targetClass.split('-')[1];
|
||
changeClass(_nodes.colorPicker, 'no-rgb-' + newMode,
|
||
(options['noRGB' + newMode] = !options['noRGB' + newMode]) ? undefined : '');
|
||
buttonAction = 'noRGB' + newMode;
|
||
// preRenderAll();
|
||
} else if (target === _nodes.alpha_labl) { // alpha button right (background of raster)
|
||
customBG = options.customBG;
|
||
alphaBG = options.alphaBG;
|
||
changeClass(_nodes.colorPicker, 'alpha-bg-' + alphaBG, 'alpha-bg-' +
|
||
(alphaBG = options.alphaBG = e.data || (alphaBG === 'w' ? (customBG ? 'c' : 'b') :
|
||
alphaBG === 'c' ? 'b' : 'w')));
|
||
target.firstChild.data = alphaBG.toUpperCase();
|
||
_nodes.ctrl.style.backgroundColor = _nodes.memo.style.backgroundColor =
|
||
alphaBG !== 'c' ? '' : 'rgb(' + Math.round(customBG.r * 255) + ', ' +
|
||
Math.round(customBG.g * 255) + ', ' +
|
||
Math.round(customBG.b * 255) + ')';
|
||
_nodes.raster.style.cssText = _nodes.raster_bg.previousSibling.style.cssText =
|
||
alphaBG !== 'c' ? '' : getOpacityCSS(customBG.luminance < 0.22 ? 0.5 : 0.4);
|
||
buttonAction = 'alphaBackground';
|
||
} else if (target === _nodes.alpha_butt) { // alpha button left (disable alpha rendering)
|
||
changeClass(_nodes.colorPicker, 'mute-alpha', (options.muteAlpha = !options.muteAlpha) ? undefined : '');
|
||
buttonAction = 'alphaState';
|
||
} else if (target === _nodes.HEX_butt) { // make it on/off
|
||
changeClass(_nodes.colorPicker, 'no-HEX', (options.HEXState = !options.HEXState) ? undefined : '');
|
||
buttonAction = 'HEXState';
|
||
} else if (target === _nodes.HEX_labl) { // web save state change
|
||
var isWebSave = _colors.saveColor === 'web save';
|
||
|
||
if (_colors.saveColor !== 'web smart' && !isWebSave) {
|
||
options.webUnsave = copyColor(RGB);
|
||
_colorPicker.setColor(_colors.webSmart, 'rgb');
|
||
} else if (!isWebSave) {
|
||
if (!options.webUnsave) {
|
||
options.webUnsave = copyColor(RGB);
|
||
}
|
||
_colorPicker.setColor(_colors.webSave, 'rgb');
|
||
} else {
|
||
_colorPicker.setColor(options.webUnsave, 'rgb');
|
||
}
|
||
buttonAction = 'webColorState';
|
||
} else if (/Lab-x-labl/.test(targetClass)) { //target === _nodes.cmyk_type) {
|
||
// switch between CMYK and CMY
|
||
changeClass(_nodes.colorPicker, 'cmy-only', (options.cmyOnly = !options.cmyOnly) ? undefined : '');
|
||
buttonAction = 'cmykState';
|
||
}
|
||
} else if (target === _nodes.bsav) { // SAVE
|
||
saveAsBackground();
|
||
buttonAction = 'saveAsBackground';
|
||
} else if (target === _nodes.bres) { // RESET
|
||
var tmpColor = copyColor(RGB),
|
||
tmpAlpha = _colors.alpha;
|
||
|
||
// a bit heavy but... doesn't matter here
|
||
// newCol, type, alpha, forceRender
|
||
_colorPicker.setColor(options.color);
|
||
saveAsBackground();
|
||
_colorPicker.setColor(tmpColor, 'rgb', tmpAlpha);
|
||
buttonAction = 'resetColor';
|
||
} else if (parent === _nodes.col1) { // COLOR left
|
||
// _colors.hsv.h = (_colors.hsv.h + 0.5) % 1; // not acurate
|
||
_colors.hsv.h -= (_colors.hsv.h > 0.5 ? 0.5 : -0.5);
|
||
convertColors('hsv');
|
||
buttonAction = 'shiftColor';
|
||
|
||
} else if (parent === _nodes.col2) { // COLOR right
|
||
_colorPicker.setColor(target.style.backgroundColor, 'rgb', _colors.background.alpha);
|
||
buttonAction = 'setSavedColor';
|
||
} else if (parent === _nodes.memo) { // MEMORIES // revisit...
|
||
var resetBlink = function() {
|
||
if (_nodes.memos.blinker) _nodes.memos.blinker.style.cssText = _nodes.memos.cssText;
|
||
},
|
||
doBlink = function(elm) {
|
||
_nodes.memos.blinker = elm;
|
||
elm.style.cssText = 'background-color:' + (_colors.RGBLuminance > 0.22 ? '#333' : '#DDD');
|
||
window.setTimeout(resetBlink, 200);
|
||
};
|
||
|
||
if (target === _nodes.memo_cursor) { // save color in memo
|
||
resetBlink();
|
||
_nodes.memos.blinker = undefined;
|
||
_nodes.testNode.style.cssText = _nodes.memo_store.style.cssText;
|
||
_nodes.memos.cssText = _nodes.testNode.style.cssText; // ...how browser sees css
|
||
for (var n = _nodes.memos.length - 1; n--; ) { // check if color already exists
|
||
if (_nodes.memos.cssText === _nodes.memos[n].style.cssText) {
|
||
doBlink(_nodes.memos[n]); // sets _nodes.memos.blinker
|
||
break;
|
||
}
|
||
}
|
||
if (!_nodes.memos.blinker) { // right shift colors
|
||
for (var n = _nodes.memos.length - 1; n--; ) {
|
||
_nodes.memos[n + 1].style.cssText = _nodes.memos[n].style.cssText;
|
||
}
|
||
_nodes.memos[0].style.cssText = _nodes.memo_store.style.cssText;
|
||
}
|
||
buttonAction = 'toMemery';
|
||
} else { // reset color from memo
|
||
resetBlink();
|
||
_colorPicker.setColor(target.style.backgroundColor, 'rgb', target.style.opacity || 1);
|
||
_nodes.memos.cssText = target.style.cssText;
|
||
doBlink(target);
|
||
// this is dirty... has to do with M|W|! button
|
||
_mouseMoveAction = 1;
|
||
buttonAction = 'fromMemory';
|
||
}
|
||
|
||
}
|
||
// think this over again, does this need to be like this??
|
||
if (buttonAction) {
|
||
preRenderAll(_colors);
|
||
_mouseMoveAction = _mouseMoveAction || true; // !!!! search for: // this is dirty...
|
||
stopChange(e, buttonAction);
|
||
}
|
||
}
|
||
|
||
function resizeApp(e, size) {
|
||
var event = e || window.event,
|
||
page = event ? getPageXY(event) : {},
|
||
isSize = size !== undefined,
|
||
x = isSize ? size : page.X - _targetOrigin.left + 8,
|
||
y = isSize ? size : page.Y - _targetOrigin.top + 8,
|
||
values = [' S XS XXS', ' S XS', ' S', ''],
|
||
sizes = _options.sizes, // from getUISizes();
|
||
value = isSize ? values[size] :
|
||
y < sizes.XXS[1] + 25 ? values[0] :
|
||
x < sizes.XS[0] + 25? values[1] :
|
||
x < sizes.S[0] + 25 || y < sizes.S[1] + 25 ? values[2] : values[3],
|
||
isXXS = false,
|
||
mode,
|
||
tmp = '';
|
||
|
||
if (_cashedVars.resizer !== value) {
|
||
isXXS = /XX/.test(value);
|
||
mode = _options.mode;
|
||
|
||
if (isXXS && (!/hs/.test(mode.type) || mode.z === 'h')) {
|
||
tmp = mode.type + '-' + mode.z;
|
||
_colorPicker.setMode(/hs/.test(mode.type) ? mode.type + '-s': 'hsv-s');
|
||
_options.mode.original = tmp;
|
||
} else if (mode.original) {
|
||
// setMode(mode) creates a new object so mode.original gets deleted automatically
|
||
_colorPicker.setMode(mode.original);
|
||
}
|
||
|
||
_nodes.colorPicker.className = _nodes.colorPicker.className.replace(/\s+(?:S|XS|XXS)/g, '') + value;
|
||
_options.scale = isXXS ? 4 : /S/.test(value) ? 2 : 1;
|
||
|
||
_cashedVars.resizer = value;
|
||
|
||
// fix this... from this point on inside if() ... convertColors();
|
||
_newData = true;
|
||
renderAll();
|
||
resetCursors();
|
||
}
|
||
|
||
_nodes.resizer.style.cssText = 'display: block;' +
|
||
'width: ' + (x > 10 ? x : 10) + 'px;' +
|
||
'height: ' + (y > 10 ? y : 10) + 'px;';
|
||
}
|
||
|
||
// ------------------------------------------------------ //
|
||
// --- Colors calculation and rendering related stuff --- //
|
||
// -------------------------------------------------------//
|
||
|
||
function setMode(mode) {
|
||
var ModeMatrix = {
|
||
rgb_r : {x: 'b', y: 'g'},
|
||
rgb_g : {x: 'b', y: 'r'},
|
||
rgb_b : {x: 'r', y: 'g'},
|
||
|
||
hsv_h : {x: 's', y: 'v'},
|
||
hsv_s : {x: 'h', y: 'v'},
|
||
hsv_v : {x: 'h', y: 's'},
|
||
|
||
hsl_h : {x: 's', y: 'l'},
|
||
hsl_s : {x: 'h', y: 'l'},
|
||
hsl_l : {x: 'h', y: 's'}
|
||
},
|
||
key = mode.replace('-', '_'),
|
||
regex = '\\b(?:rg|hs)\\w\\-\\w\\b'; // \\b\\w{3}\\-\\w\\b';
|
||
|
||
// changeClass(_nodes.colorPicker, '(?:.*?)$', mode);
|
||
// changeClass(_nodes.colorPicker, '\\b\\w{3}\\-\\w\\b', mode);
|
||
// changeClass(_nodes.slds, '\\b\\w{3}\\-\\w\\b', mode);
|
||
changeClass(_nodes.panel, regex, mode);
|
||
changeClass(_nodes.slds, regex, mode);
|
||
|
||
mode = mode.split('-');
|
||
return _options.mode = {
|
||
type: mode[0],
|
||
x: ModeMatrix[key].x,
|
||
y: ModeMatrix[key].y,
|
||
z: mode[1]
|
||
};
|
||
}
|
||
|
||
function initSliders() { // function name...
|
||
var regex = /\s+(?:hue-)*(?:dark|light)/g;
|
||
|
||
_nodes.curl.className = _nodes.curl.className.replace(regex, ''); // .....
|
||
_nodes.curr.className = _nodes.curr.className.replace(regex, ''); // .....
|
||
_nodes.slds.className = _nodes.slds.className.replace(regex, '');
|
||
// var sldrs = ['sldr_2', 'sldr_4', 'sldl_3'];
|
||
// for (var n = sldrs.length; n--; ) {
|
||
// _nodes[sldrs[n]].className = _options.CSSPrefix + sldrs[n].replace('_', '-');
|
||
// }
|
||
_nodes.sldr_2.className = _options.CSSPrefix + 'sldr-2';
|
||
_nodes.sldr_4.className = _options.CSSPrefix + 'sldr-4';
|
||
_nodes.sldl_3.className = _options.CSSPrefix + 'sldl-3';
|
||
|
||
for (var style in _nodes.styles) {
|
||
if (!style.indexOf('sld')) _nodes.styles[style].cssText = '';
|
||
}
|
||
_cashedVars = {};
|
||
}
|
||
|
||
function resetCursors() {
|
||
// _renderVars.isNoRGB = undefined;
|
||
_nodes.styles.curr.cssText = _nodes.styles.curl.cssText; // only coordinates
|
||
_nodes.curl.className = _options.CSSPrefix + 'curl' + (
|
||
_renderVars.noRGBZ ? ' ' + _options.CSSPrefix + 'curl-' +_renderVars.noRGBZ: '');
|
||
_nodes.curr.className = _options.CSSPrefix + 'curr ' + _options.CSSPrefix + 'curr-' +
|
||
(_options.mode.z === 'h' ? _renderVars.HUEContrast : _renderVars.noRGBZ ?
|
||
_renderVars.noRGBZ : _renderVars.RGBLuminance);
|
||
}
|
||
|
||
function convertColors(type) {
|
||
preRenderAll(_colorInstance.setColor(undefined, type || _options.mode.type));
|
||
_newData = true;
|
||
}
|
||
|
||
function saveAsBackground(refresh) {
|
||
_colorInstance.saveAsBackground();
|
||
_nodes.styles.col2.cssText = 'background-color: ' + color2string(_colors.background.RGB) + ';' +
|
||
getOpacityCSS(_colors.background.alpha);
|
||
|
||
if (refresh) {
|
||
preRenderAll(_colors);
|
||
// renderAll();
|
||
}
|
||
return (_colors);
|
||
}
|
||
|
||
function preRenderAll(colors) { // do we need this??? yes, only calculate if values change... but how about _newData
|
||
var renderVars = _renderVars,
|
||
bgType = _bgTypes[_options.alphaBG];
|
||
|
||
renderVars.hueDelta = Math.round(colors['rgbaMixBGMix' + bgType].hueDelta * 100);
|
||
// renderVars.RGBLuminanceDelta = Math.round(colors.RGBLuminanceDelta * 100);
|
||
renderVars.luminanceDelta = Math.round(colors['rgbaMixBGMix' + bgType].luminanceDelta * 100);
|
||
renderVars.RGBLuminance = colors.RGBLuminance > 0.22 ? 'light' : 'dark';
|
||
renderVars.HUEContrast = colors.HUELuminance > 0.22 ? 'light' : 'dark';
|
||
// renderVars.contrast = renderVars.RGBLuminanceDelta > renderVars.hueDelta ? 'contrast' : '';
|
||
renderVars.contrast = renderVars.luminanceDelta > renderVars.hueDelta ? 'contrast' : '';
|
||
renderVars.readabiltiy =
|
||
colors['rgbaMixBGMix' + bgType].WCAG2Ratio >= 7 ? 'green' :
|
||
colors['rgbaMixBGMix' + bgType].WCAG2Ratio >= 4.5 ? 'orange': '';
|
||
renderVars.noRGBZ = _options['no' + _options.mode.type.toUpperCase() + _options.mode.z] ?
|
||
(_options.mode.z === 'g' && colors.rgb.g < 0.59 || _options.mode.z === 'b' || _options.mode.z === 'r' ?
|
||
'dark' : 'light') : undefined;
|
||
}
|
||
|
||
function renderAll() { // maybe render alpha seperately...
|
||
if (_mouseMoveAction) {
|
||
// _renderTimer = window[requestAnimationFrame](renderAll);
|
||
if (!_newData) return (_renderTimer = window[requestAnimationFrame](renderAll));
|
||
_newData = false;
|
||
}
|
||
// console.time('renderAll');
|
||
var options = _options, colors = _colors, renderVars = _renderVars, cashedVars = _cashedVars,
|
||
mode = options.mode, nodes = _nodes,
|
||
prefix = options.CSSPrefix,
|
||
valueRanges = _valueRanges,
|
||
valueType = _valueType,
|
||
CSS = nodes.styles,
|
||
textNodes = nodes.textNodes,
|
||
scale = _options.scale,
|
||
x = colors[mode.type][mode.x], X = Math.round(x * 255 / (scale === 4 ? 2 : scale)),
|
||
y_ = colors[mode.type][mode.y], y = 1 - y_, Y = Math.round(y * 255 / scale),
|
||
z = 1 - colors[mode.type][mode.z], Z = Math.round(z * 255 / scale),
|
||
coords = (1 === 1) ? [x, y_] : [0, 0], a = 0, b = 0, // (1 === 2) button label up
|
||
isRGB = mode.type === 'rgb', isHue = mode.z === 'h', isHSL = mode.type === 'hsl',
|
||
isHSL_S = isHSL && mode.z === 's',
|
||
display, tmp, value, slider,
|
||
moveXY = _mouseMoveAction === changeXYValue, moveZ = _mouseMoveAction === changeZValue;
|
||
|
||
if (isRGB) {
|
||
if (coords[0] >= coords[1]) b = 1; else a = 1;
|
||
if (cashedVars.sliderSwap !== a) {
|
||
nodes.sldr_2.className = options.CSSPrefix + 'sldr-' + (3 - a);
|
||
cashedVars.sliderSwap = a;
|
||
}
|
||
}
|
||
if ((isRGB && !moveZ) || (isHue && !moveXY) || (!isHue && !moveZ)) {
|
||
CSS[isHue ? 'sldl_2' : 'sldr_2'][isRGB ? 'cssText' : 'backgroundColor'] =
|
||
isRGB ? getOpacityCSS((coords[a] - coords[b]) / (1 - (coords[b]) || 0)) : color2string(colors.hueRGB);
|
||
}
|
||
if (!isHue) {
|
||
if (!moveZ) CSS.sldr_4.cssText = getOpacityCSS(isRGB ? coords[b] : isHSL_S ? Math.abs(1 - y * 2) : y);
|
||
if (!moveXY) CSS.sldl_3.cssText = getOpacityCSS(isHSL && mode.z === 'l' ? Math.abs(1 - z * 2) : z);
|
||
if (isHSL) { // switch slider class name for black/white color half way through in HSL(S|L) mode(s)
|
||
slider = isHSL_S ? 'sldr_4' : 'sldl_3';
|
||
tmp = isHSL_S ? 'r-' : 'l-';
|
||
value = isHSL_S ? (y > 0.5 ? 4 : 3) : (z > 0.5 ? 3 : 4);
|
||
|
||
if (cashedVars[slider] !== value) {
|
||
nodes[slider].className = options.CSSPrefix + 'sld' + tmp + value;
|
||
cashedVars[slider] = value;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!moveZ) CSS.curm.cssText = 'left: ' + X + 'px; top: ' + Y + 'px;';
|
||
if (!moveXY) CSS.curl.top = Z + 'px';
|
||
if (valueType) CSS.curr.top = Z + 'px'; // && valueType.type !== mode.type
|
||
if ((valueType && valueType.type === 'alpha') || _mainTarget === nodes.opacity) {
|
||
CSS.opacity_slider.left = options.opacityPositionRelative ? (colors.alpha * (
|
||
(_targetOrigin.width || nodes.opacity.offsetWidth) -
|
||
(_targetOrigin.childWidth || nodes.opacity_slider.offsetWidth))) + 'px' :
|
||
(colors.alpha * 100) + '%';
|
||
}
|
||
|
||
CSS.col1.cssText = 'background-color: ' + color2string(colors.RND.rgb) + '; ' +
|
||
(options.muteAlpha ? '' : getOpacityCSS(colors.alpha));
|
||
CSS.opacity.backgroundColor = color2string(colors.RND.rgb);
|
||
CSS.cold.width = renderVars.hueDelta + '%';
|
||
CSS.cont.width = renderVars.luminanceDelta + '%';
|
||
|
||
for (display in textNodes) {
|
||
tmp = display.split('_');
|
||
if (options.cmyOnly) {
|
||
tmp[0] = tmp[0].replace('k', '');
|
||
}
|
||
value = tmp[1] ? colors.RND[tmp[0]][tmp[1]] : colors.RND[tmp[0]] || colors[tmp[0]];
|
||
if (cashedVars[display] !== value) {
|
||
cashedVars[display] = value;
|
||
textNodes[display].data = value > 359.5 && display !== 'HEX' ? 0 : value;
|
||
|
||
if (display !== 'HEX' && !options.noRangeBackground) {
|
||
value = colors[tmp[0]][tmp[1]] !== undefined ? colors[tmp[0]][tmp[1]] : colors[tmp[0]];
|
||
if (tmp[0] === 'Lab') {
|
||
value = (value - valueRanges[tmp[0]][tmp[1]][0]) /
|
||
(valueRanges[tmp[0]][tmp[1]][1] - valueRanges[tmp[0]][tmp[1]][0]);
|
||
}
|
||
CSS[display].backgroundPosition = Math.round((1 - value) * 100) + '% 0%';
|
||
}
|
||
}
|
||
}
|
||
// Lab out of gammut
|
||
tmp = colors._rgb ? [
|
||
colors._rgb.r !== colors.rgb.r,
|
||
colors._rgb.g !== colors.rgb.g,
|
||
colors._rgb.b !== colors.rgb.b
|
||
] : [];
|
||
if (tmp.join('') !== cashedVars.outOfGammut) {
|
||
nodes.rgb_r_labl.firstChild.data = tmp[0] ? '!' : ' ';
|
||
nodes.rgb_g_labl.firstChild.data = tmp[1] ? '!' : ' ';
|
||
nodes.rgb_b_labl.firstChild.data = tmp[2] ? '!' : ' ';
|
||
cashedVars.outOfGammut = tmp.join('');
|
||
}
|
||
if (renderVars.noRGBZ) {
|
||
if (cashedVars.noRGBZ !== renderVars.noRGBZ) {
|
||
nodes.curl.className = prefix + 'curl ' + prefix + 'curl-' + renderVars.noRGBZ;
|
||
|
||
if (!moveZ) {
|
||
nodes.curr.className = prefix + 'curr ' + prefix + 'curr-' + renderVars.noRGBZ;
|
||
}
|
||
cashedVars.noRGBZ = renderVars.noRGBZ;
|
||
}
|
||
}
|
||
if (cashedVars.HUEContrast !== renderVars.HUEContrast && mode.z === 'h') {
|
||
nodes.slds.className = nodes.slds.className.replace(/\s+hue-(?:dark|light)/, '') +
|
||
' hue-' + renderVars.HUEContrast;
|
||
if (!moveZ) {
|
||
nodes.curr.className = prefix + 'curr ' + prefix + 'curr-' + renderVars.HUEContrast;
|
||
}
|
||
cashedVars.HUEContrast = renderVars.HUEContrast;
|
||
} else if (cashedVars.RGBLuminance !== renderVars.RGBLuminance) { // test for no else
|
||
nodes.colorPicker.className = nodes.colorPicker.className.replace(/\s+(?:dark|light)/, '') +
|
||
' ' + renderVars.RGBLuminance;
|
||
if (!moveZ && mode.z !== 'h' && !renderVars.noRGBZ) {
|
||
nodes.curr.className = prefix + 'curr ' + prefix + 'curr-' + renderVars.RGBLuminance;
|
||
}
|
||
cashedVars.RGBLuminance = renderVars.RGBLuminance;
|
||
}
|
||
|
||
if (cashedVars.contrast !== renderVars.contrast || cashedVars.readabiltiy !== renderVars.readabiltiy) {
|
||
nodes.ctrl.className = nodes.ctrl.className.replace(' contrast', '').replace(/\s*(?:orange|green)/, '') +
|
||
(renderVars.contrast ? ' ' + renderVars.contrast : '') +
|
||
(renderVars.readabiltiy ? ' ' + renderVars.readabiltiy : '');
|
||
cashedVars.contrast = renderVars.contrast;
|
||
cashedVars.readabiltiy = renderVars.readabiltiy;
|
||
}
|
||
|
||
if (cashedVars.saveColor !== colors.saveColor) {
|
||
nodes.HEX_labl.firstChild.data = !colors.saveColor ? '!' : colors.saveColor === 'web save' ? 'W' : 'M';
|
||
cashedVars.saveColor = colors.saveColor;
|
||
}
|
||
|
||
if (options.renderCallback) {
|
||
options.renderCallback(colors, mode); // maybe more parameters
|
||
}
|
||
|
||
if (_mouseMoveAction) {
|
||
_renderTimer = window[requestAnimationFrame](renderAll);
|
||
}
|
||
|
||
// console.timeEnd('renderAll')
|
||
}
|
||
|
||
|
||
// ------------------------------------------------------ //
|
||
// ------------------ helper functions ------------------ //
|
||
// -------------------------------------------------------//
|
||
|
||
function copyColor(color) {
|
||
var newColor = {};
|
||
|
||
for (var n in color) {
|
||
newColor[n] = color[n];
|
||
}
|
||
return newColor;
|
||
}
|
||
|
||
// function color2string(color, type) {
|
||
// var out = [],
|
||
// n = 0;
|
||
|
||
// type = type || 'rgb';
|
||
// while (type.charAt(n)) { // IE7 // V8 type[n] ||
|
||
// out.push(color[type.charAt(n)]);
|
||
// n++;
|
||
// }
|
||
// return type + '(' + out.join(', ') + ')';
|
||
// }
|
||
|
||
function color2string(color, type) { // ~2 x faster on V8
|
||
var out = '',
|
||
t = (type || 'rgb').split(''),
|
||
n = t.length;
|
||
|
||
for ( ; n--; ) {
|
||
out = ', ' + color[t[n]] + out;
|
||
}
|
||
return (type || 'rgb') + '(' + out.substr(2) + ')';
|
||
}
|
||
|
||
|
||
function limitValue(value, min, max) {
|
||
// return Math.max(min, Math.min(max, value)); // faster??
|
||
return (value > max ? max : value < min ? min : value);
|
||
}
|
||
|
||
function getOpacityCSS(value) {
|
||
if (value === undefined) value = 1;
|
||
|
||
if (_isIE) {
|
||
return 'filter: alpha(opacity=' + Math.round(value * 100) + ');';
|
||
} else {
|
||
return 'opacity: ' + (Math.round(value * 10000000000) / 10000000000) + ';'; // value.toFixed(16) = 99% slower
|
||
// some speed test:
|
||
// return ['opacity: ', (Math.round(value * 1e+10) / 1e+10), ';'].join('');
|
||
}
|
||
}
|
||
|
||
function preventDefault(e, skip) {
|
||
e.preventDefault ? e.preventDefault() : e.returnValue = false;
|
||
if (!skip) window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
|
||
return false;
|
||
}
|
||
|
||
function changeClass(elm, cln, newCln) {
|
||
return !elm ? false : elm.className = (newCln !== undefined ?
|
||
elm.className.replace(new RegExp('\\s+?' + cln, 'g'), newCln ? ' ' + newCln : '') :
|
||
elm.className + ' ' + cln);
|
||
}
|
||
|
||
function getOrigin(elm) {
|
||
var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {top: 0, left: 0},
|
||
doc = elm && elm.ownerDocument,
|
||
body = doc.body,
|
||
win = doc.defaultView || doc.parentWindow || window,
|
||
docElem = doc.documentElement || body.parentNode,
|
||
clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
|
||
clientLeft = docElem.clientLeft || body.clientLeft || 0;
|
||
|
||
return {
|
||
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
|
||
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
|
||
};
|
||
}
|
||
|
||
function getPageXY(e) {
|
||
return {
|
||
X: e.pageX || e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
|
||
Y: e.pageY || e.clientY + document.body.scrollTop + document.documentElement.scrollTop
|
||
};
|
||
}
|
||
|
||
function addEvent(obj, type, func) {
|
||
addEvent.cache = addEvent.cache || {
|
||
_get: function(obj, type, func, checkOnly) {
|
||
var cache = addEvent.cache[type] || [];
|
||
|
||
for (var n = cache.length; n--; ) {
|
||
if (obj === cache[n].obj && '' + func === '' + cache[n].func) {
|
||
func = cache[n].func;
|
||
if (!checkOnly) {
|
||
cache[n] = cache[n].obj = cache[n].func = null;
|
||
cache.splice(n, 1);
|
||
}
|
||
return func;
|
||
}
|
||
}
|
||
},
|
||
_set: function(obj, type, func) {
|
||
var cache = addEvent.cache[type] = addEvent.cache[type] || [];
|
||
|
||
if (addEvent.cache._get(obj, type, func, true)) {
|
||
return true;
|
||
} else {
|
||
cache.push({
|
||
func: func,
|
||
obj: obj
|
||
});
|
||
}
|
||
}
|
||
};
|
||
|
||
if (!func.name && addEvent.cache._set(obj, type, func) || typeof func !== 'function') {
|
||
return;
|
||
}
|
||
|
||
if (obj.addEventListener) obj.addEventListener(type, func, false);
|
||
else obj.attachEvent('on' + type, func);
|
||
}
|
||
|
||
function removeEvent(obj, type, func) {
|
||
if (typeof func !== 'function') return;
|
||
if (!func.name) {
|
||
func = addEvent.cache._get(obj, type, func) || func;
|
||
}
|
||
|
||
if (obj.removeEventListener) obj.removeEventListener(type, func, false);
|
||
else obj.detachEvent('on' + type, func);
|
||
}
|
||
|
||
function caret(target, pos) { // only for contenteditable
|
||
var out = {};
|
||
|
||
if (pos === undefined) { // get
|
||
if (window.getSelection) { // HTML5
|
||
target.focus();
|
||
var range1 = window.getSelection().getRangeAt(0),
|
||
range2 = range1.cloneRange();
|
||
range2.selectNodeContents(target);
|
||
range2.setEnd(range1.endContainer, range1.endOffset);
|
||
out = {
|
||
end: range2.toString().length,
|
||
range: range1.toString().length
|
||
};
|
||
} else { // IE < 9
|
||
target.focus();
|
||
var range1 = document.selection.createRange(),
|
||
range2 = document.body.createTextRange();
|
||
range2.moveToElementText(target);
|
||
range2.setEndPoint('EndToEnd', range1);
|
||
out = {
|
||
end: range2.text.length,
|
||
range: range1.text.length
|
||
};
|
||
}
|
||
out.start = out.end - out.range;
|
||
return out;
|
||
}
|
||
// set
|
||
if (pos == -1) pos = target['text']().length;
|
||
|
||
if (window.getSelection) { // HTML5
|
||
target.focus();
|
||
window.getSelection().collapse(target.firstChild, pos);
|
||
} else { // IE < 9
|
||
var range = document.body.createTextRange();
|
||
range.moveToElementText(target);
|
||
range.moveStart('character', pos);
|
||
range.collapse(true);
|
||
range.select();
|
||
}
|
||
return pos;
|
||
}
|
||
|
||
// ------------- requestAnimationFrame shim ------------- //
|
||
// ---------- quite optimized for minification ---------- //
|
||
|
||
for(var n = vendors.length; n-- && !window[requestAnimationFrame]; ) {
|
||
window[requestAnimationFrame] = window[vendors[n] + 'Request' + animationFrame];
|
||
window[cancelAnimationFrame] = window[vendors[n] + 'Cancel' + animationFrame] ||
|
||
window[vendors[n] + 'CancelRequest' + animationFrame];
|
||
}
|
||
|
||
window[requestAnimationFrame] = window[requestAnimationFrame] || function(callback) {
|
||
// this is good enough... and better than setTimeout
|
||
return window.setTimeout(callback, 1000 / _options.fps);
|
||
// return _renderTimer ? _renderTimer : window.setInterval(callback, 1000 / _options.fps);
|
||
};
|
||
|
||
window[cancelAnimationFrame] = window[cancelAnimationFrame] || function(id) {
|
||
// console.log('OFF-', id + '-' + _renderTimer)
|
||
window.clearTimeout(id);
|
||
return _renderTimer = null;
|
||
};
|
||
|
||
})(window); |