MFColorPicker / 1.03 / js / mf-colorpicker.min.js file last updated : 2024-03-23 |
---|
/*! methodfish package release
Project : MFColorPicker
Release : 1.03
Release date : 2024-03-21 16:39:10
License : MIT
For more information please refer to https://methodfish.com/Projects/MFColorPicker
*/
/*
Improved color selector; implement by including the js and then using the following html you get the
standard html color picker, but this will also maintain the list of default colors and store them in
a named element so that this can be re-used if desired.
To assist in the UX, this class will also add a tick button to the right of the standard input (I find
it wrong that the "Other" color selector doesn't have a OK button. Note, it would be good to add a cross,
but this is not possible as the selector is a modal popup.
The selector also maintains the list of colors including the latest color at the front of the list
This class requires material-icons to have the tick work.
<link rel="stylesheet preload prefetch" as="style" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<input type="hidden" id="mfpresets" value="ffffff,000000,ff0000,00f000,0000ff">
<input type="color" class="mfcolor" onchange="alert()">
<script>
const _mfcolorpicker = new MFColorPicker();
_mfcolorpicker.init('mfpresets');
</script>
*/
const _MFC_COMPLEMENTARY='COMP';
const _MFC_ANALOGOUS = 'ANALO';
const _MFC_TRIADIC = 'TRIADIC';
const _MFC_SPLITCOMP = 'SPLIT';
function MFColorPicker() {
var _gridSize=150;
var _csvPresetElemId;
var _selectedColor;
var _selectedv;
var _transparency;
var _darkness;
var _targetV0;
var _target;
var _activeMFColorPicker=false;
//--------------------------------------
function showColorPicker(target, but, presetId, n) {
_target = target;
_targetV0 = target.value;
document.querySelectorAll('.mfcolorpicker-container').forEach(function(el) {
el.remove();
});
if ( n==undefined ) n=_gridSize;
let container = document.querySelector('.container');
if ( !container ) {
container = document.createElement('div');
container.className = 'mfcolorpicker-container removeOnEscape removeOnResize';
}
container.style.left = but.getBoundingClientRect().left+'px';
container.style.top = (but.getBoundingClientRect().bottom + window.pageYOffset) + 'px';
container.style.zIndex = getMaxZIndex()+1;
document.body.appendChild(container);
// ------------ color picker
container.appendChild(getColorPicker(n));
let bottom = document.createElement('div');
bottom.style.padding='20px';
bottom.style.margin='0';
bottom.style.borderTop='solid 1px #dcd8dc';
container.appendChild(bottom);
let v = colToRGBA(_target.value); // 'rgba(0,0,0,1)';
// ------------ darkness
let darknessLine = document.createElement('div');
darknessLine.style.padding='0';
darknessLine.style.margin='0';
bottom.appendChild(darknessLine);
if ( 1 ) {
let darkness = document.createElement('input');
darkness.className = 'mfcolorpicker-darkness';
darkness.title = 'Color darkness';
darkness.type = 'range';
darkness.setAttribute('min', -255);
darkness.setAttribute('max', 255);
darkness.setAttribute('step', 1);
darkness.value = 0;
darknessLine.appendChild(darkness);
_darkness = darkness;
darkness.addEventListener('input', function (e) {
let amt = e.target.value;
let rgb = adjustColorBrightness(e.target.getAttribute('data-orig'), e.target.value);
let alpha = _transparency.value;
let rgba = rgb.replace(')', `,${alpha})`).replace(/rgb\(/, 'rgba(');
setSelectedColor(rgba);
setSelectedColor(rgba);
setSelectedTarget(_target, rgba);
});
darkness.style.background = 'linear-gradient(to right, black, '+v+', white)';
darkness.setAttribute('data-orig', v);
}
// ------------ transparency
let transparencyLine = document.createElement('div');
transparencyLine.className = ''
transparencyLine.style.padding='0';
transparencyLine.style.margin='0';
bottom.appendChild(transparencyLine);
if ( 1 ) {
let transparencySlider = document.createElement('div');
transparencySlider.className = 'mfcolorpicker-checkerboard mfcolorpicker-checkerboard-wrapper'
transparencySlider.style.padding='0';
transparencySlider.style.margin='0';
transparencySlider.title = 'Color transparency';
transparencyLine.appendChild(transparencySlider);
let transparencyChecker = document.createElement('div');
transparencyChecker.className = 'mfcolorpicker-checkerboard-underlay';
transparencySlider.appendChild(transparencyChecker);
let transparency = document.createElement('input');
transparency.className = 'mfcolorpicker-transparency';
transparency.type = 'range';
transparency.setAttribute('min', 0);
transparency.setAttribute('max', 1);
transparency.setAttribute('step', 0.01);
transparencySlider.appendChild(transparency);
_transparency = transparency;
transparency.addEventListener('input', function () {
let picker = document.querySelector('.mfcolorpicker-picker');
picker.style.opacity = transparency.value;
transparencyv.innerHTML = (parseFloat(transparency.value) * 100) + '%';
let rgb = _selectedColor.getAttribute('data-selected');
if (rgb.startsWith('#')) rgb = hexToRGBA(rgb);
let parts = rgb.substring(rgb.indexOf('(')+1).split(',');
let rgba = `rgba(${parts[0].trim()}, ${parts[1].trim()}, ${parts[2].trim()}, ${transparency.value})`;
_selectedColor.style.backgroundColor = rgba;
// let selectedValue = document.querySelector('.mfcolorpicker-selectedvalue');
// if (selectedValue.getAttribute('data-type') == 'hex') {
// let hex = rgbaToHex(rgba);
// selectedValue.innerHTML = hex;
// }
// else {
// selectedValue.innerHTML = rgba;
// }
setSelectedColor(rgba);
setSelectedColor(rgba);
setSelectedTarget(_target, rgba);
});
let transparencyv = document.createElement('span');
transparencyv.className = 'mfcolorpicker-transparencyvalue';
transparencyv.innerHTML = '100%';
transparencyLine.appendChild(transparencyv);
}
// ------------ eye dropper
if (window.EyeDropper) { // this only works on https domains
let eyedropperButton = document.createElement('i');
eyedropperButton.className = 'material-icons mfcolorpicker-eyedropper';
eyedropperButton.innerHTML = 'colorize';
bottom.appendChild(eyedropperButton);
eyedropperButton.addEventListener('click', async () => {
const eyeDropper = new EyeDropper();
eyeDropper
.open()
.then((result) => {
let rgba = colToRGBA(result.sRGBHex+'ff');
setSelectedColor(rgba);
setSelectedTarget(_target, rgba);
})
.catch((e) => {
console.error(e);
});
});
}
else {
console.warn('No EyeDropper available on this browser');
}
// ------------ selected color sample
let selectedContainer = document.createElement('div');
selectedContainer.className = 'mfcolorpicker-presets-pair mfcolorpicker-selected-color';
bottom.appendChild(selectedContainer);
if ( 1 ) {
let selectedColorBg = document.createElement('div');
selectedColorBg.className = 'mfcolorpicker-selected-bg mfcolorpicker-checkerboard';
selectedContainer.appendChild(selectedColorBg);
_selectedColor = document.createElement('div');
_selectedColor.className = 'mfcolorpicker-selected';
selectedContainer.appendChild(_selectedColor);
}
// ------------ selectedvalue text
let selectedv = document.createElement('span');
selectedv.className = 'mfcolorpicker-selectedvalue';
bottom.appendChild(selectedv);
selectedv.addEventListener('click', function() {
if ( selectedv.getAttribute('data-type')=='hex' ) selectedv.setAttribute('data-type','rgb');
else selectedv.setAttribute('data-type','hex');
showSelectedValue( _selectedColor.getAttribute('data-selected'));
});
_selectedv = selectedv;
// ------------ complementary colors
bottom.appendChild(getCompsContainer());
// ------------ presets group
let presets = getPresets(presetId);
if ( presets ) bottom.appendChild(presets);
setSelectedColor(v);
let buttons = document.createElement('div');
buttons.className = 'mfcolorpicker-buttons';
bottom.appendChild(buttons);
let ok = document.createElement('button');
ok.className = 'mfcolorpicker-button';
ok.innerHTML='OK';
buttons.appendChild(ok);
ok.addEventListener('click', function() {
let v= _selectedColor.getAttribute('data-selected');
setSelectedTarget(_target, v);
triggerElementEvent(_target, 'change');
container.remove();
})
let cancel = document.createElement('button');
cancel.className = 'mfcolorpicker-button';
cancel.innerHTML='Cancel';
buttons.appendChild(cancel);
cancel.addEventListener('click', function() {
setSelectedColor(_targetV0);
setSelectedTarget(_target, _targetV0);
container.remove();
})
moveDivOnscreen(container);
_activeMFColorPicker = true;
document.querySelector('.mfcolorpicker-comps-container > SELECT').addEventListener('change', showCompsPatch);
document.querySelector('.mfcolorpicker-comps-container > SELECT').addEventListener('input', showCompsPatch);
setTimeout(function() {
showCompsPatch();
},1);
}
//--------------------------------------
function adjustColorBrightness(rgb, darkness) {
let parts=rgb.substring(rgb.indexOf('(')+1).split(',');
darkness = parseInt(darkness);
let r = clamp(parseInt(parts[0]) + darkness, 0, 255);
let g = clamp(parseInt(parts[1]) + darkness, 0, 255);
let b = clamp(parseInt(parts[2]) + darkness, 0, 255);
let result =`rgb(${r}, ${g}, ${b})`;
return result;
}
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
//--------------------------------------
function getMfDefaultColList(presetId) {
if ( presetId ) {
let el = document.querySelector('#' + presetId);
if (el) return el.value;
}
return 'ffffff,000000,ababab,d7d7d7,d7d7d7,e6dee0,c00000,ea0000,ff0505,ff5001,ed7d31,375623,548235,00b050,a9d18e,e2f0d9';
}
//--------------------------------------
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
//--------------------------------------
function getMaxZIndex() {
let elems= document.querySelectorAll('div');
let max=0;
for(let i=0;i<elems.length;i++) {
let t=getComputed(elems[i],'z-index');
if ( t!='auto' ) {
if (isNumeric(t) && parseInt(t) > max) {
max = parseInt(t);
}
}
}
elems=document.getElementsByTagName('canvas');
for(let i=0;i<elems.length;i++) {
let t=getComputed(elems[i],'z-index'); // elems[i].style.zIndex;
if ( isNumeric(t) && parseInt(t)>max ) {
max=parseInt(t);
}
}
return parseInt(max);
}
//--------------------------------------
function getComputed(elem, rule) {
if (!elem) return null;
let styles = window.getComputedStyle(elem);
let result = styles.getPropertyValue(rule);
return result;
}
//--------------------------------------
function colToHex(v) {
if ( v.startsWith('#')) return v;
else return rgbaToHex(v);
}
//--------------------------------------
function colToRGBA(v) {
if ( v.startsWith('rgba') ) return v;
if ( v.startsWith('rgb') ) {
return v.replace(')', ', 1)');
}
return hexToRGBA(v);
}
//--------------------------------------
function getCompsContainer() {
let compsContainer = document.createElement('span');
compsContainer.className = 'mfcolorpicker-comps-container';
let selector = document.createElement('SELECT');
selector.innerHTML = '<option value="COMP">Complementary</option>'
+ '<option value="ANALO">Analogous</option>'
+ '<option value="TRIADIC">Triadic</option>'
+ '<option value="SPLIT" title="Split-complementary">Split-comp</option>';
compsContainer.appendChild(selector);
let colors = document.createElement('DIV');
colors.className = 'mfcolorpicker-colorblock';
compsContainer.appendChild(colors);
return compsContainer;
}
function showCompsPatch() {
if ( !document.querySelector('.mfcolorpicker-comps-container > SELECT')) return;
let typeCd = document.querySelector('.mfcolorpicker-comps-container > SELECT').value;
let rgba= document.querySelector('.mfcolorpicker-selected').style.backgroundColor;
let colorblock= document.querySelector('.mfcolorpicker-comps-container > .mfcolorpicker-colorblock');
let samples = document.querySelectorAll('.mfcolorpicker-colorblock .sample');
if ( samples ) samples.forEach(function(sample) { sample.remove()});
let sample = document.createElement('div');
sample.className = 'sample';
sample.style.backgroundColor = rgba;
sample.title = rgba;
colorblock.appendChild(sample);
let colors = getComps(rgba, typeCd);
for(let c=0; c<colors.length; c++) {
rgba = colors[c];
let sample = document.createElement('div');
sample.className = 'sample';
sample.style.backgroundColor = rgba;
sample.title = rgba;
colorblock.appendChild(sample);
sample.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
let rgba = e.target.style.backgroundColor;
if ( rgba.startsWith('rgb(')) rgba='rgba('+rgba.substring(4, rgba.length-1)+', 1)';
setSelectedColor(rgba);
let darkness = document.querySelector('.mfcolorpicker-darkness');
darkness.style.background = 'linear-gradient(to right, black, '+rgba+', white)';
darkness.setAttribute('data-orig', rgba);
darkness.value = 0;
});
}
}
function getComps(rgbaColor, typeCd) {
const colors = [];
// Parse the RGBA color
let [r, g, b, a] = rgbaColor.match(/(\d+(\.\d+)?)/g).map(Number);
if ( a==undefined ) a=1;
// Complementary color
switch (typeCd) {
case _MFC_COMPLEMENTARY:
const complementaryR = 255 - r;
const complementaryG = 255 - g;
const complementaryB = 255 - b;
colors.push(`rgba(${complementaryR}, ${complementaryG}, ${complementaryB}, ${a})`);
break;
case _MFC_ANALOGOUS:
// Analogous colors
const analogous1 = rotateHue(r, g, b, -30);
const analogous2 = rotateHue(r, g, b, 30);
colors.push(`rgba(${analogous1[0]}, ${analogous1[1]}, ${analogous1[2]}, ${a})`);
colors.push(`rgba(${analogous2[0]}, ${analogous2[1]}, ${analogous2[2]}, ${a})`);
break;
case _MFC_TRIADIC:
// Triadic colors
const triadic1 = rotateHue(r, g, b, 120);
const triadic2 = rotateHue(r, g, b, 240);
colors.push(`rgba(${triadic1[0]}, ${triadic1[1]}, ${triadic1[2]}, ${a})`);
colors.push(`rgba(${triadic2[0]}, ${triadic2[1]}, ${triadic2[2]}, ${a})`);
break;
case _MFC_SPLITCOMP:
// Split-complementary colors
const splitComplementary1 = rotateHue(r, g, b, 72); // -150);
const splitComplementary2 = rotateHue(r, g, b, 216); // -30);
colors.push(`rgba(${splitComplementary1[0]}, ${splitComplementary1[1]}, ${splitComplementary1[2]}, ${a})`);
colors.push(`rgba(${splitComplementary2[0]}, ${splitComplementary2[1]}, ${splitComplementary2[2]}, ${a})`);
break;
default:
console.error('Invalid type code give '+typeCd);
}
return colors;
}
function rotateHue(r, g, b, angle) {
// Convert RGB to HSL
let hsl = rgbToHsl(r, g, b);
// Rotate the hue
hsl[0] += angle / 360;
// Convert back to RGB
let rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
return rgb;
}
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
let max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h, s, l];
}
function hslToRgb(h, s, l) {
let r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
let p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
//--------------------------------------
function getPresets(presetId) {
if ( !document.querySelector('#'+presetId) ) return null;
var presets = document.createElement('div');
presets.className = 'mfcolorpicker-presets-container';
let presetCols=document.querySelector('#'+presetId).value.replace(/#/g,'').split(',');
presetCols.forEach(function(optv) {
let presetsColorPair = document.createElement('div');
presetsColorPair.className = 'mfcolorpicker-presets-pair preset';
presets.appendChild(presetsColorPair);
let presetColorBg = document.createElement('div');
presetColorBg.className = 'mfcolorpicker-preset mfcolorpicker-checkerboard';
presetsColorPair.appendChild(presetColorBg);
let presetColor = document.createElement('div');
presetColor.className = 'mfcolorpicker-preset';
let c = colToRGBA('#'+optv);
presetColor.style.backgroundColor = c;
presetsColorPair.appendChild(presetColor);
presetColor.addEventListener('click', function() {
let rgba = colToRGBA(optv);
setSelectedColor(rgba);
setSelectedTarget(_target, rgba);
let parts = rgba.replace(/rgba\(/, '').split(',');
let rgb = `rgb(${parseInt(parts[0])}, ${parseInt(parts[1])}, ${parseInt(parts[2])})`;
let darkness = document.querySelector('.mfcolorpicker-darkness');
darkness.style.background = 'linear-gradient(to right, black, '+rgb+', white)';
darkness.setAttribute('data-orig', rgb);
darkness.value=0;
})
});
return presets;
}
//-----------------------------------------------------------------------------------------
function triggerElementEvent(elem, eventType) {
let elems=[elem];
for(let i=0;i<elems.length; i++) {
if (eventType == undefined) eventType = 'change';
if ("createEvent" in document) {
let evt = document.createEvent("HTMLEvents");
evt.initEvent(eventType, true, true);
if ( elems[i] ) elems[i].dispatchEvent(evt); // trigger Events
}
else {
elems[i].fireEvent("on" + eventType);
}
}
}
//--------------------------------------
function getColorPicker(n) {
let picker = document.querySelector('.mfcolorpicker-picker');
if (!picker) {
picker = document.createElement('div');
picker.className = 'mfcolorpicker-picker';
}
picker.style.gridTemplateColumns = `repeat(${n}, 1fr)`;
picker.style.gridTemplateRows = `repeat(${n}, 1fr)`;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
const brightness = (i / (n - 1)) * 100; // Calculate brightness from top to bottom
const hue = (j / (n - 1)) * 360; // Calculate hue from left to right
const saturation = 100;
const transparency = 1;
const color = `hsla(${hue}, ${saturation}%, ${brightness}%, ${transparency})`;
const colorBox = document.createElement('div');
colorBox.classList.add('mfcolorpicker-color-box');
colorBox.style.backgroundColor = color;
picker.appendChild(colorBox);
colorBox.addEventListener('mouseover', function (e) {
e.preventDefault();
e.stopPropagation();
const regex = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;
const v = e.target.style.backgroundColor;
const [, r, g, b] = v.match(regex) || [];
let rgb = v;
let transparency = _transparency.value;
let rgba = rgb.replace('rgb', 'rgba').replace(')', `, ${transparency})`);
_selectedColor.style.backgroundColor = rgba;
showSelectedValue(rgba);
setSelectedTarget(_target, rgba);
});
colorBox.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
document.querySelector('.mfcolorpicker-darkness').value = 0;
let transparency = _transparency.value;
const rgb = e.target.style.backgroundColor;
let rgba = rgb.replace('rgb', 'rgba').replace(')', `, ${transparency})`);
setSelectedColor(rgba);
let darkness = document.querySelector('.mfcolorpicker-darkness');
darkness.style.background = 'linear-gradient(to right, black, '+rgba+', white)';
darkness.setAttribute('data-orig', rgba);
//console.log('----------------------------------- Click selected '+rgba);
});
}
}
picker.addEventListener('mouseout', function (e) {
let v = _selectedColor.getAttribute('data-selected');
if (v) {
//console.log('\n\n\n--------------------------------- Switching back to '+v);
let rgba= v;
_selectedColor.style.backgroundColor = rgba;
showSelectedValue(rgba);
setSelectedColor(rgba);
setSelectedTarget(_target, rgba);
}
});
return picker;
}
//-----------------------------------------------------------------------------------------
function getElemInfo(elem) {
if ( !elem ) return '[null]';
let result = elem.tagName;
if (elem.id) result += '#' + elem.id;
if (elem.className) result += '.' + elem.className;
if ( 1 ) {
result+=' tx='+elem.innerText.substring(0, 20).trim().replace(/\n/g, '{LF}');
if ( elem.innerText.length>20 ) result+='...';
}
return '[' + result + ']';
}
//--------------------------------------
function getAlpha(rgba) {
let match = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/);
if (match) {
// Extract the alpha value and convert it to a percentage
let alpha = parseFloat(match[4]);
let alphaPercentage = alpha * 100;
return alphaPercentage;
} else {
return null; // Return null if the background color is not in RGBA format
}
}
//--------------------------------------
function hexToRGBA(hex) {
if ( hex.startsWith('rgb')) return colToRGBA(hex);
hex = hex.replace(/^#/, '');// Remove # if present
if ( hex.length==6) hex+='FF';
// Parse hexadecimal string to RGB values
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
let a = parseInt(parseInt(hex.substring(6, 8), 16) / 255 * 100)/100; // Convert alpha from [0, 255] to [0, 1]
// Return the RGBA values as an object
return `rgba(${r}, ${g}, ${b}, ${a})`;
}
//--------------------------------------
function setSelectedColor(v) {
if ( _selectedColor ) {
_selectedColor.style.backgroundColor = v;
_selectedColor.setAttribute('data-selected', v);
let parts = v.split(',');
parts[3] = "0)"; // Set the alpha value to 0
let vx = parts.join(',');
parts[3] = "1)"; // Set the alpha value to 0
let vxx = parts.join(',');
_transparency.style.background = `linear-gradient(to right, ${vx}, ${vxx})`;
showSelectedValue(v);
_transparency.value = getAlpha(v) / 100;
let picker = document.querySelector('.mfcolorpicker-picker');
if (picker) {
picker.style.opacity = _transparency.value;
document.querySelector('.mfcolorpicker-transparencyvalue').innerHTML = parseInt(parseFloat(_transparency.value) * 100) + '%';
}
}
}
//--------------------------------------
function showSelectedValue(v) {
if (_selectedv.getAttribute('data-type') == 'hex') {
_selectedv.innerHTML = rgbaToHex(v);
}
else {
_selectedv.innerHTML = v;
}
if ( _selectedv.innerHTML.indexOf('NaN')>-1 ) debugger;
showCompsPatch();
}
//--------------------------------------
function rgbaToHex(rgba) {
if ( !rgba ) debugger;
if ( rgba.startsWith('#')) return rgba;
if (rgba) {
let parts = rgba.substring(5, rgba.length - 1).split(",");
let r = parseInt(parts[0]);
let g = parseInt(parts[1]);
let b = parseInt(parts[2]);
let a = 1;
if ( parts.length>2 ) a = parseFloat(parts[3]); // Parse alpha as float
// Convert alpha value to integer (0-255) before converting to hex
let alphaHex = Math.round(a * 255).toString(16).padStart(2, '0');
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b) + alphaHex;
}
return ''; // Return empty string if rgba is empty
}
//--------------------------------------
function componentToHex(c) {
let hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
//--------------------------------------
function initMfColorButton(elem, presetId) {
elem.style.display='none';
elem.addEventListener('change', function() {
mfSaveColor(elem);
});
if ( presetId ) elem.setAttribute('list', presetId);
var pair = document.createElement('div');
pair.className= 'mfcolorpicker-presets-pair mfcolorpicker-current-color '+elem.className;
removeClassName(pair, 'hidden');
elem.parentNode.insertBefore(pair, elem.nextElementSibling);
if ( 1 ) {
var bg = document.createElement('div');
bg.className = 'mfcolorpicker-color-button mfcolorpicker-checkerboard';
pair.appendChild(bg);
var but = document.createElement('div');
but.className = 'mfcolorpicker-color-button';
but.innerHTML = ' ';
but.style.backgroundColor = elem.value;
pair.appendChild(but);
but.addEventListener('click', function () {
showColorPicker(elem, but, presetId);
});
}
}
//------------------------------------------------------------------------------------
function removeClassName(elem, classNm) {
if (!elem) return;
const regex = new RegExp('\\b' + classNm + '\\b', 'g');
elem.className = elem.className.replace(regex, '').trim();
}
//------------------------------------------------------------------------------------
function moveDivOnscreen(elem, container) {
let viewportWidth;
let containerLeft = 0;
let adj = 5;
let scrollX = window.scrollX || window.pageXOffset; // Get the horizontal scroll position
let scrollY = window.scrollY || window.pageYOffset; // Get the vertical scroll position
if (container === undefined) container = window;
if (container === window) viewportWidth = window.innerWidth - adj;
else {
containerLeft = container.getBoundingClientRect().left;
viewportWidth = container.getBoundingClientRect().width - adj;
}
let viewportHeight;
if (container === window) viewportHeight = window.innerHeight - adj;
else viewportHeight = container.getBoundingClientRect().height - adj;
// Get the bounding rectangle of the element
const elemRect = elem.getBoundingClientRect();
// Calculate the desired position of the element relative to the viewport
let newTop = (elemRect.top + window.pageYOffset + adj); // Maintain the current top position
let newLeft = (elemRect.left + window.pageXOffset); // Maintain the current left position
// Adjust the left position if the element exceeds the viewport width
if ((elemRect.right - containerLeft) > viewportWidth) {
newLeft -= (elemRect.right - containerLeft - viewportWidth + 2*adj);
}
// Adjust the top position if the element exceeds the viewport height
if (elemRect.bottom > viewportHeight) {
newTop -= (elemRect.bottom - viewportHeight + 2*adj);
}
// Adjust the top position if the element's top is above the viewport
if (elemRect.top < 0) {
newTop -= (elemRect.top - scrollY + 2*adj);
}
// Set the new position of the element
elem.style.top = newTop + 'px';
elem.style.left = newLeft + 'px';
}
//---------------------------------------
function mfSaveColor(elem) {
var listElem = document.querySelector('#'+_csvPresetElemId);
// Add the new colour to the csv list
if (listElem) {
var csv = listElem.value;
var vals = csv.split(',');
var col = elem.value.replace(/#/,'');
if (!vals.includes(col)) {
if (elem.value != '') {
listElem.value = col + ',' + csv;
doBuildListElem();
}
}
}
}
//---------------------------------------
function doBuildListElem() {
var list = document.querySelector('#'+_csvPresetElemId+'list');
if (!list) {
list = document.createElement('datalist');
list.id = _csvPresetElemId+'list';
document.body.appendChild(list);
}
var cols = getMfDefaultColList(_csvPresetElemId).split(',');
list.innerHTML='';
for (var c = 0; c < cols.length; c++) {
list.innerHTML += '<option>#' + cols[c].toUpperCase() + '</option>';
}
}
//------------------------------------------------------------------------------------
function addClassName(elem, classNm) {
if ( elem.id == 'wysiwyg' ) debugger;
const regex = new RegExp('\\b' + classNm + '\\b', 'g');
if (!regex.test(elem.className)) elem.className += ' ' + classNm;
}
//---------------------------------------
function hasClassName(elem, classNm) {
const regex = new RegExp('\\b' + classNm + '\\b');
return regex.test(elem.classList);
}
//---------------------------------------
function setSelectedTarget(target, v) {
if ( !target ) return;
target.type='text';
let hex = colToHex(v);
target.value = hex;
target.nextElementSibling.children[1].style.backgroundColor=hexToRGBA(hex);
triggerElementEvent(_target, 'input');
showCompsPatch();
}
//------------------------------------------------------------------------------------
function getParentElem(elem, classNm) {
while (elem) {
if (hasClassName(elem, classNm)) return elem;
elem = elem.parentElement;
}
return elem;
}
//---------------------------------------
return {
colToHex(v){
return colToHex(v);
}
,colToRGBA(v) {
return colToRGBA(v);
}
,setSelectedTarget(target, v) {
setSelectedTarget(target, v);
}
,init(csvPresetElemId, gridSize) {
if ( gridSize!=undefined ) _gridSize = gridSize;
_csvPresetElemId = csvPresetElemId;
doBuildListElem();
var inputs = document.querySelectorAll('input.mfcolorpicker');
for (var i = 0; i < inputs.length; i++) {
if ( !hasClassName(inputs[i], 'mfcolorpicker-ready')) {
inputs[i].className+=' mfcolorpicker-ready';
if ( !inputs[i].value ) inputs[i].value='#ffffff';
initMfColorButton(inputs[i], csvPresetElemId);
}
}
if ( !hasClassName(document.body, 'mfcolorpicker-events') ) {
addClassName(document.body, 'mfcolorpicker-events');
window.addEventListener('click', function (e) {
if (e.target) {
if (e.target.className && hasClassName(e.target, 'removeOnEscape')) return;
if (e.target.className && hasClassName(e.target, 'mfcolorpicker-color-button')) return;
if (getParentElem(e.target, 'mfcolorpicker-container') != null) return;
}
if (_activeMFColorPicker) {
setSelectedColor(_targetV0);
setSelectedTarget(_target, _targetV0);
document.querySelectorAll('.removeOnEscape').forEach(function (el) {
if (el.close) el.close;
else el.remove();
});
}
});
window.addEventListener('resize', event => {
setSelectedColor(_targetV0);
if (_target) setSelectedTarget(_target, _targetV0);
document.querySelectorAll('.removeOnResize').forEach(function (el) {
el.remove();
_activeMFColorPicker = false;
});
});
window.addEventListener('keydown', event => {
if (event.key === 'Escape') {
if (window.EyeDropper) {
const eyeDropper = new EyeDropper();
eyeDropper.close();
}
setSelectedColor(_targetV0);
setSelectedTarget(_target, _targetV0);
document.querySelectorAll('.removeOnEscape').forEach(function (el) {
if (el.close) el.close;
else el.remove();
});
_activeMFColorPicker = false;
}
});
}
}
}
}
Also see
articles/HTML-hex-color-codessquarearticles/Implementing-a-Monaco-Editorsquarearticles/iConnectionTestsquarearticles/javascript-camerasquarearticles/list-editsquarearticles/minifierssquarearticles/opayosquarearticles/table-drag-sortersquarearticles/typewatchsquareprojects/MFCalendarPopupsquareprojects/MFChartColumnsquareprojects/MFColorPickersquareprojects/MFColorPickerBasicsquareprojects/MFColumnGradientsquareprojects/MFFloatawayMsgsquareprojects/MFPanelssquareprojects/MFSelectorsquare
Comments
New Comment