raspap-webgui/dist/huebee/huebee.pkgd.js

1126 lines
28 KiB
JavaScript

/*!
* Huebee PACKAGED v2.1.0
* 1-click color picker
* MIT license
* https://huebee.buzz
* Copyright 2020 Metafizzy
*/
/**
* EvEmitter v1.1.0
* Lil' event emitter
* MIT License
*/
/* jshint unused: true, undef: true, strict: true */
( function( global, factory ) {
// universal module definition
/* jshint strict: false */ /* globals define, module, window */
if ( typeof define == 'function' && define.amd ) {
// AMD - RequireJS
define( 'ev-emitter/ev-emitter',factory );
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS - Browserify, Webpack
module.exports = factory();
} else {
// Browser globals
global.EvEmitter = factory();
}
}( typeof window != 'undefined' ? window : this, function() {
"use strict";
function EvEmitter() {}
var proto = EvEmitter.prototype;
proto.on = function( eventName, listener ) {
if ( !eventName || !listener ) {
return;
}
// set events hash
var events = this._events = this._events || {};
// set listeners array
var listeners = events[ eventName ] = events[ eventName ] || [];
// only add once
if ( listeners.indexOf( listener ) == -1 ) {
listeners.push( listener );
}
return this;
};
proto.once = function( eventName, listener ) {
if ( !eventName || !listener ) {
return;
}
// add event
this.on( eventName, listener );
// set once flag
// set onceEvents hash
var onceEvents = this._onceEvents = this._onceEvents || {};
// set onceListeners object
var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
// set flag
onceListeners[ listener ] = true;
return this;
};
proto.off = function( eventName, listener ) {
var listeners = this._events && this._events[ eventName ];
if ( !listeners || !listeners.length ) {
return;
}
var index = listeners.indexOf( listener );
if ( index != -1 ) {
listeners.splice( index, 1 );
}
return this;
};
proto.emitEvent = function( eventName, args ) {
var listeners = this._events && this._events[ eventName ];
if ( !listeners || !listeners.length ) {
return;
}
// copy over to avoid interference if .off() in listener
listeners = listeners.slice(0);
args = args || [];
// once stuff
var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
for ( var i=0; i < listeners.length; i++ ) {
var listener = listeners[i]
var isOnce = onceListeners && onceListeners[ listener ];
if ( isOnce ) {
// remove listener
// remove before trigger to prevent recursion
this.off( eventName, listener );
// unset once flag
delete onceListeners[ listener ];
}
// trigger listener
listener.apply( this, args );
}
return this;
};
proto.allOff = function() {
delete this._events;
delete this._onceEvents;
};
return EvEmitter;
}));
/*!
* Unipointer v2.3.0
* base class for doing one thing with pointer event
* MIT license
*/
/*jshint browser: true, undef: true, unused: true, strict: true */
( function( window, factory ) {
// universal module definition
/* jshint strict: false */ /*global define, module, require */
if ( typeof define == 'function' && define.amd ) {
// AMD
define( 'unipointer/unipointer',[
'ev-emitter/ev-emitter'
], function( EvEmitter ) {
return factory( window, EvEmitter );
});
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory(
window,
require('ev-emitter')
);
} else {
// browser global
window.Unipointer = factory(
window,
window.EvEmitter
);
}
}( window, function factory( window, EvEmitter ) {
'use strict';
function noop() {}
function Unipointer() {}
// inherit EvEmitter
var proto = Unipointer.prototype = Object.create( EvEmitter.prototype );
proto.bindStartEvent = function( elem ) {
this._bindStartEvent( elem, true );
};
proto.unbindStartEvent = function( elem ) {
this._bindStartEvent( elem, false );
};
/**
* Add or remove start event
* @param {Boolean} isAdd - remove if falsey
*/
proto._bindStartEvent = function( elem, isAdd ) {
// munge isAdd, default to true
isAdd = isAdd === undefined ? true : isAdd;
var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener';
// default to mouse events
var startEvent = 'mousedown';
if ( window.PointerEvent ) {
// Pointer Events
startEvent = 'pointerdown';
} else if ( 'ontouchstart' in window ) {
// Touch Events. iOS Safari
startEvent = 'touchstart';
}
elem[ bindMethod ]( startEvent, this );
};
// trigger handler methods for events
proto.handleEvent = function( event ) {
var method = 'on' + event.type;
if ( this[ method ] ) {
this[ method ]( event );
}
};
// returns the touch that we're keeping track of
proto.getTouch = function( touches ) {
for ( var i=0; i < touches.length; i++ ) {
var touch = touches[i];
if ( touch.identifier == this.pointerIdentifier ) {
return touch;
}
}
};
// ----- start event ----- //
proto.onmousedown = function( event ) {
// dismiss clicks from right or middle buttons
var button = event.button;
if ( button && ( button !== 0 && button !== 1 ) ) {
return;
}
this._pointerDown( event, event );
};
proto.ontouchstart = function( event ) {
this._pointerDown( event, event.changedTouches[0] );
};
proto.onpointerdown = function( event ) {
this._pointerDown( event, event );
};
/**
* pointer start
* @param {Event} event
* @param {Event or Touch} pointer
*/
proto._pointerDown = function( event, pointer ) {
// dismiss right click and other pointers
// button = 0 is okay, 1-4 not
if ( event.button || this.isPointerDown ) {
return;
}
this.isPointerDown = true;
// save pointer identifier to match up touch events
this.pointerIdentifier = pointer.pointerId !== undefined ?
// pointerId for pointer events, touch.indentifier for touch events
pointer.pointerId : pointer.identifier;
this.pointerDown( event, pointer );
};
proto.pointerDown = function( event, pointer ) {
this._bindPostStartEvents( event );
this.emitEvent( 'pointerDown', [ event, pointer ] );
};
// hash of events to be bound after start event
var postStartEvents = {
mousedown: [ 'mousemove', 'mouseup' ],
touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
};
proto._bindPostStartEvents = function( event ) {
if ( !event ) {
return;
}
// get proper events to match start event
var events = postStartEvents[ event.type ];
// bind events to node
events.forEach( function( eventName ) {
window.addEventListener( eventName, this );
}, this );
// save these arguments
this._boundPointerEvents = events;
};
proto._unbindPostStartEvents = function() {
// check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)
if ( !this._boundPointerEvents ) {
return;
}
this._boundPointerEvents.forEach( function( eventName ) {
window.removeEventListener( eventName, this );
}, this );
delete this._boundPointerEvents;
};
// ----- move event ----- //
proto.onmousemove = function( event ) {
this._pointerMove( event, event );
};
proto.onpointermove = function( event ) {
if ( event.pointerId == this.pointerIdentifier ) {
this._pointerMove( event, event );
}
};
proto.ontouchmove = function( event ) {
var touch = this.getTouch( event.changedTouches );
if ( touch ) {
this._pointerMove( event, touch );
}
};
/**
* pointer move
* @param {Event} event
* @param {Event or Touch} pointer
* @private
*/
proto._pointerMove = function( event, pointer ) {
this.pointerMove( event, pointer );
};
// public
proto.pointerMove = function( event, pointer ) {
this.emitEvent( 'pointerMove', [ event, pointer ] );
};
// ----- end event ----- //
proto.onmouseup = function( event ) {
this._pointerUp( event, event );
};
proto.onpointerup = function( event ) {
if ( event.pointerId == this.pointerIdentifier ) {
this._pointerUp( event, event );
}
};
proto.ontouchend = function( event ) {
var touch = this.getTouch( event.changedTouches );
if ( touch ) {
this._pointerUp( event, touch );
}
};
/**
* pointer up
* @param {Event} event
* @param {Event or Touch} pointer
* @private
*/
proto._pointerUp = function( event, pointer ) {
this._pointerDone();
this.pointerUp( event, pointer );
};
// public
proto.pointerUp = function( event, pointer ) {
this.emitEvent( 'pointerUp', [ event, pointer ] );
};
// ----- pointer done ----- //
// triggered on pointer up & pointer cancel
proto._pointerDone = function() {
this._pointerReset();
this._unbindPostStartEvents();
this.pointerDone();
};
proto._pointerReset = function() {
// reset properties
this.isPointerDown = false;
delete this.pointerIdentifier;
};
proto.pointerDone = noop;
// ----- pointer cancel ----- //
proto.onpointercancel = function( event ) {
if ( event.pointerId == this.pointerIdentifier ) {
this._pointerCancel( event, event );
}
};
proto.ontouchcancel = function( event ) {
var touch = this.getTouch( event.changedTouches );
if ( touch ) {
this._pointerCancel( event, touch );
}
};
/**
* pointer cancel
* @param {Event} event
* @param {Event or Touch} pointer
* @private
*/
proto._pointerCancel = function( event, pointer ) {
this._pointerDone();
this.pointerCancel( event, pointer );
};
// public
proto.pointerCancel = function( event, pointer ) {
this.emitEvent( 'pointerCancel', [ event, pointer ] );
};
// ----- ----- //
// utility function for getting x/y coords from event
Unipointer.getPointerPoint = function( pointer ) {
return {
x: pointer.pageX,
y: pointer.pageY
};
};
// ----- ----- //
return Unipointer;
}));
/*!
* Huebee v2.1.0
* 1-click color picker
* MIT license
* https://huebee.buzz
* Copyright 2020 Metafizzy
*/
/* jshint browser: true, unused: true, undef: true */
( function( window, factory ) {
// universal module definition
if ( typeof define == 'function' && define.amd ) {
/* globals define */ // AMD
define( [
'ev-emitter/ev-emitter',
'unipointer/unipointer',
], function( EvEmitter, Unipointer ) {
return factory( window, EvEmitter, Unipointer );
} );
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory(
window,
require('ev-emitter'),
require('unipointer')
);
} else {
// browser global
window.Huebee = factory(
window,
window.EvEmitter,
window.Unipointer
);
}
}( window, function factory( window, EvEmitter, Unipointer ) {
function Huebee( anchor, options ) {
// anchor
anchor = getQueryElement( anchor );
if ( !anchor ) {
throw new Error( 'Bad element for Huebee: ' + anchor );
}
this.anchor = anchor;
// options
this.options = {};
this.option( Huebee.defaults );
this.option( options );
// kick things off
this.create();
}
Huebee.defaults = {
hues: 12,
hue0: 0,
shades: 5,
saturations: 3,
notation: 'shortHex',
setText: true,
setBGColor: true,
};
var proto = Huebee.prototype = Object.create( EvEmitter.prototype );
proto.option = function( options ) {
this.options = extend( this.options, options );
};
// globally unique identifiers
var GUID = 0;
// internal store of all Colcade intances
var instances = {};
proto.create = function() {
// add guid for Colcade.data
var guid = this.guid = ++GUID;
this.anchor.huebeeGUID = guid;
instances[ guid ] = this; // associate via id
// properties
this.setBGElems = this.getSetElems( this.options.setBGColor );
this.setTextElems = this.getSetElems( this.options.setText );
// events
// HACK: this is getting ugly
this.outsideCloseIt = this.outsideClose.bind( this );
this.onDocKeydown = this.docKeydown.bind( this );
this.closeIt = this.close.bind( this );
this.openIt = this.open.bind( this );
this.onElemTransitionend = this.elemTransitionend.bind( this );
// open events
this.isInputAnchor = this.anchor.nodeName == 'INPUT';
if ( !this.options.staticOpen ) {
this.anchor.addEventListener( 'click', this.openIt );
this.anchor.addEventListener( 'focus', this.openIt );
}
// change event
if ( this.isInputAnchor ) {
this.anchor.addEventListener( 'input', this.inputInput.bind( this ) );
}
// create element
var element = this.element = document.createElement('div');
element.className = 'huebee ';
element.className += this.options.staticOpen ? 'is-static-open ' :
'is-hidden ';
element.className += this.options.className || '';
// create container
var container = this.container = document.createElement('div');
container.className = 'huebee__container';
// do not blur if padding clicked
function onContainerPointerStart( event ) {
if ( event.target == container ) {
event.preventDefault();
}
}
container.addEventListener( 'mousedown', onContainerPointerStart );
container.addEventListener( 'touchstart', onContainerPointerStart );
// create canvas
this.createCanvas();
// create cursor
this.cursor = document.createElement('div');
this.cursor.className = 'huebee__cursor is-hidden';
container.appendChild( this.cursor );
// create close button
this.createCloseButton();
element.appendChild( container );
// set relative position on parent
if ( !this.options.staticOpen ) {
var parentStyle = getComputedStyle( this.anchor.parentNode );
if ( parentStyle.position != 'relative' && parentStyle.position != 'absolute' ) {
this.anchor.parentNode.style.position = 'relative';
}
}
// satY, y position where saturation grid starts
var customLength = this.getCustomLength();
this.satY = customLength ? Math.ceil( customLength / this.options.hues ) + 1 : 0;
// colors
this.updateColors();
this.setAnchorColor();
if ( this.options.staticOpen ) {
this.open();
}
};
proto.getSetElems = function( option ) {
if ( option === true ) {
return [ this.anchor ];
} else if ( typeof option == 'string' ) {
return document.querySelectorAll( option );
}
};
proto.getCustomLength = function() {
var customColors = this.options.customColors;
return customColors && customColors.length || 0;
};
proto.createCanvas = function() {
var canvas = this.canvas = document.createElement('canvas');
canvas.className = 'huebee__canvas';
this.ctx = canvas.getContext('2d');
// canvas pointer events
var canvasPointer = this.canvasPointer = new Unipointer();
canvasPointer._bindStartEvent( canvas );
canvasPointer.on( 'pointerDown', this.canvasPointerDown.bind( this ) );
canvasPointer.on( 'pointerMove', this.canvasPointerMove.bind( this ) );
this.container.appendChild( canvas );
};
var svgURI = 'http://www.w3.org/2000/svg';
proto.createCloseButton = function() {
if ( this.options.staticOpen ) {
return;
}
var svg = document.createElementNS( svgURI, 'svg' );
svg.setAttribute( 'class', 'huebee__close-button' );
svg.setAttribute( 'viewBox', '0 0 24 24' );
svg.setAttribute( 'width', '24' );
svg.setAttribute( 'height', '24' );
var path = document.createElementNS( svgURI, 'path' );
path.setAttribute( 'd', 'M 7,7 L 17,17 M 17,7 L 7,17' );
path.setAttribute( 'class', 'huebee__close-button__x' );
svg.appendChild( path );
svg.addEventListener( 'click', this.closeIt );
this.container.appendChild( svg );
};
proto.updateColors = function() {
// hash of color, h, s, l according to x,y grid position
// [x,y] = { color, h, s, l }
this.swatches = {};
// hash of gridX,gridY position according to color
// [#09F] = { x, y }
this.colorGrid = {};
this.updateColorModer();
var shades = this.options.shades;
var sats = this.options.saturations;
var hues = this.options.hues;
// render custom colors
if ( this.getCustomLength() ) {
var customI = 0;
this.options.customColors.forEach( function( color ) {
var x = customI % hues;
var y = Math.floor( customI/hues );
var swatch = getSwatch( color );
if ( swatch ) {
this.addSwatch( swatch, x, y );
customI++;
}
}.bind( this ) );
}
// render saturation grids
var i;
for ( i = 0; i < sats; i++ ) {
var sat = 1 - i/sats;
var yOffset = shades * i + this.satY;
this.updateSaturationGrid( i, sat, yOffset );
}
// render grays
var grayCount = this.getGrayCount();
for ( i = 0; i < grayCount; i++ ) {
var lum = 1 - i / ( shades + 1 );
var color = this.colorModer( 0, 0, lum );
var swatch = getSwatch( color );
this.addSwatch( swatch, hues + 1, i );
}
};
// get shades + black & white; else 0
proto.getGrayCount = function() {
return this.options.shades ? this.options.shades + 2 : 0;
};
proto.updateSaturationGrid = function( i, sat, yOffset ) {
var shades = this.options.shades;
var hues = this.options.hues;
var hue0 = this.options.hue0;
for ( var row = 0; row < shades; row++ ) {
for ( var col = 0; col < hues; col++ ) {
var hue = Math.round( col * 360/hues + hue0 ) % 360;
var lum = 1 - ( row + 1 ) / ( shades + 1 );
var color = this.colorModer( hue, sat, lum );
var swatch = getSwatch( color );
var gridY = row + yOffset;
this.addSwatch( swatch, col, gridY );
}
}
};
proto.addSwatch = function( swatch, gridX, gridY ) {
// add swatch color to hash
this.swatches[ gridX + ',' + gridY ] = swatch;
// add color to colorGrid
this.colorGrid[ swatch.color.toUpperCase() ] = {
x: gridX,
y: gridY,
};
};
var colorModers = {
hsl: function( h, s, l ) {
s = Math.round( s * 100 );
l = Math.round( l * 100 );
return 'hsl(' + h + ', ' + s + '%, ' + l + '%)';
},
hex: hsl2hex,
shortHex: function( h, s, l ) {
var hex = hsl2hex( h, s, l );
return roundHex( hex );
},
};
proto.updateColorModer = function() {
this.colorModer = colorModers[ this.options.notation ] || colorModers.shortHex;
};
proto.renderColors = function() {
var gridSize = this.gridSize * 2;
for ( var position in this.swatches ) {
var swatch = this.swatches[ position ];
var duple = position.split(',');
var gridX = duple[0];
var gridY = duple[1];
this.ctx.fillStyle = swatch.color;
this.ctx.fillRect( gridX * gridSize, gridY * gridSize, gridSize, gridSize );
}
};
proto.setAnchorColor = function() {
if ( this.isInputAnchor ) {
this.setColor( this.anchor.value );
}
};
// ----- events ----- //
var docElem = document.documentElement;
proto.open = function() {
/* jshint unused: false */
if ( this.isOpen ) {
return;
}
var anchor = this.anchor;
var elem = this.element;
if ( !this.options.staticOpen ) {
elem.style.left = anchor.offsetLeft + 'px';
elem.style.top = anchor.offsetTop + anchor.offsetHeight + 'px';
}
this.bindOpenEvents( true );
elem.removeEventListener( 'transitionend', this.onElemTransitionend );
// add huebee to DOM
anchor.parentNode.insertBefore( elem, anchor.nextSibling );
// measurements
var duration = getComputedStyle( elem ).transitionDuration;
this.hasTransition = duration && duration != 'none' && parseFloat( duration );
this.isOpen = true;
this.updateSizes();
this.renderColors();
this.setAnchorColor();
// trigger reflow for transition
/* eslint-disable-next-line no-unused-vars */
var h = elem.offsetHeight;
elem.classList.remove('is-hidden');
};
proto.bindOpenEvents = function( isAdd ) {
if ( this.options.staticOpen ) {
return;
}
var method = ( isAdd ? 'add' : 'remove' ) + 'EventListener';
docElem[ method ]( 'mousedown', this.outsideCloseIt );
docElem[ method ]( 'touchstart', this.outsideCloseIt );
document[ method ]( 'focusin', this.outsideCloseIt );
document[ method ]( 'keydown', this.onDocKeydown );
this.anchor[ method ]( 'blur', this.closeIt );
};
proto.updateSizes = function() {
var hues = this.options.hues;
var shades = this.options.shades;
var sats = this.options.saturations;
var grayCount = this.getGrayCount();
var customLength = this.getCustomLength();
this.cursorBorder = parseInt( getComputedStyle( this.cursor ).borderTopWidth, 10 );
this.gridSize = Math.round( this.cursor.offsetWidth - this.cursorBorder * 2 );
this.canvasOffset = {
x: this.canvas.offsetLeft,
y: this.canvas.offsetTop,
};
var cols, rows;
if ( customLength && !grayCount ) {
// custom colors only
cols = Math.min( customLength, hues );
rows = Math.ceil( customLength/hues );
} else {
cols = hues + 2;
rows = Math.max( shades * sats + this.satY, grayCount );
}
var width = this.canvas.width = cols * this.gridSize * 2;
this.canvas.height = rows * this.gridSize * 2;
this.canvas.style.width = width/2 + 'px';
};
// close if target is not anchor or element
proto.outsideClose = function( event ) {
var isAnchor = this.anchor.contains( event.target );
var isElement = this.element.contains( event.target );
if ( !isAnchor && !isElement ) {
this.close();
}
};
var closeKeydowns = {
13: true, // enter
27: true, // esc
};
proto.docKeydown = function( event ) {
if ( closeKeydowns[ event.keyCode ] ) {
this.close();
}
};
var supportsTransitions = typeof docElem.style.transform == 'string';
proto.close = function() {
if ( !this.isOpen ) {
return;
}
if ( supportsTransitions && this.hasTransition ) {
this.element.addEventListener( 'transitionend', this.onElemTransitionend );
} else {
this.remove();
}
this.element.classList.add('is-hidden');
this.bindOpenEvents( false );
this.isOpen = false;
};
proto.remove = function() {
var parent = this.element.parentNode;
if ( parent.contains( this.element ) ) {
parent.removeChild( this.element );
}
};
proto.elemTransitionend = function( event ) {
if ( event.target != this.element ) {
return;
}
this.element.removeEventListener( 'transitionend', this.onElemTransitionend );
this.remove();
};
proto.inputInput = function() {
this.setColor( this.anchor.value );
};
// ----- canvas pointer ----- //
proto.canvasPointerDown = function( event, pointer ) {
event.preventDefault();
this.updateOffset();
this.canvasPointerChange( pointer );
};
proto.updateOffset = function() {
var boundingRect = this.canvas.getBoundingClientRect();
this.offset = {
x: boundingRect.left + window.pageXOffset,
y: boundingRect.top + window.pageYOffset,
};
};
proto.canvasPointerMove = function( event, pointer ) {
this.canvasPointerChange( pointer );
};
proto.canvasPointerChange = function( pointer ) {
var x = Math.round( pointer.pageX - this.offset.x );
var y = Math.round( pointer.pageY - this.offset.y );
var gridSize = this.gridSize;
var sx = Math.floor( x/gridSize );
var sy = Math.floor( y/gridSize );
var swatch = this.swatches[ sx + ',' + sy ];
this.setSwatch( swatch );
};
// ----- select ----- //
proto.setColor = function( color ) {
var swatch = getSwatch( color );
this.setSwatch( swatch );
};
proto.setSwatch = function( swatch ) {
var color = swatch && swatch.color;
if ( !swatch ) {
return;
}
var wasSameColor = color == this.color;
// color properties
this.color = color;
this.hue = swatch.hue;
this.sat = swatch.sat;
this.lum = swatch.lum;
// estimate if color can have dark or white text
var lightness = this.lum - Math.cos( ( this.hue + 70 )/180 * Math.PI ) * 0.15;
this.isLight = lightness > 0.5;
// cursor
var gridPosition = this.colorGrid[ color.toUpperCase() ];
this.updateCursor( gridPosition );
// set texts & backgrounds
this.setTexts();
this.setBackgrounds();
// event
if ( !wasSameColor ) {
this.emitEvent( 'change', [ color, swatch.hue, swatch.sat, swatch.lum ] );
}
};
proto.setTexts = function() {
if ( !this.setTextElems ) {
return;
}
for ( var i = 0; i < this.setTextElems.length; i++ ) {
var elem = this.setTextElems[i];
var property = elem.nodeName == 'INPUT' ? 'value' : 'textContent';
elem[ property ] = this.color;
}
};
proto.setBackgrounds = function() {
if ( !this.setBGElems ) {
return;
}
var textColor = this.isLight ? '#222' : 'white';
for ( var i = 0; i < this.setBGElems.length; i++ ) {
var elem = this.setBGElems[i];
elem.style.backgroundColor = this.color;
elem.style.color = textColor;
}
};
proto.updateCursor = function( position ) {
if ( !this.isOpen ) {
return;
}
// show cursor if color is on the grid
var classMethod = position ? 'remove' : 'add';
this.cursor.classList[ classMethod ]('is-hidden');
if ( !position ) {
return;
}
var gridSize = this.gridSize;
var offset = this.canvasOffset;
var border = this.cursorBorder;
this.cursor.style.left = position.x * gridSize + offset.x - border + 'px';
this.cursor.style.top = position.y * gridSize + offset.y - border + 'px';
};
// -------------------------- htmlInit -------------------------- //
var console = window.console;
function htmlInit() {
var elems = document.querySelectorAll('[data-huebee]');
for ( var i = 0; i < elems.length; i++ ) {
var elem = elems[i];
var attr = elem.getAttribute('data-huebee');
var options;
try {
options = attr && JSON.parse( attr );
} catch ( error ) {
// log error, do not initialize
if ( console ) {
console.error( 'Error parsing data-huebee on ' + elem.className +
': ' + error );
}
continue;
}
// initialize
new Huebee( elem, options );
}
}
var readyState = document.readyState;
if ( readyState == 'complete' || readyState == 'interactive' ) {
htmlInit();
} else {
document.addEventListener( 'DOMContentLoaded', htmlInit );
}
// -------------------------- Huebee.data -------------------------- //
Huebee.data = function( elem ) {
elem = getQueryElement( elem );
var id = elem && elem.huebeeGUID;
return id && instances[ id ];
};
// -------------------------- getSwatch -------------------------- //
// proxy canvas used to check colors
var proxyCanvas = document.createElement('canvas');
proxyCanvas.width = proxyCanvas.height = 1;
var proxyCtx = proxyCanvas.getContext('2d');
function getSwatch( color ) {
// check that color value is valid
proxyCtx.clearRect( 0, 0, 1, 1 );
proxyCtx.fillStyle = '#010203'; // reset value
proxyCtx.fillStyle = color;
proxyCtx.fillRect( 0, 0, 1, 1 );
var data = proxyCtx.getImageData( 0, 0, 1, 1 ).data;
// convert to array, imageData not array, #10
data = [ data[0], data[1], data[2], data[3] ];
if ( data.join(',') == '1,2,3,255' ) {
// invalid color
return;
}
// convert rgb to hsl
var hsl = rgb2hsl.apply( this, data );
return {
color: color.trim(),
hue: hsl[0],
sat: hsl[1],
lum: hsl[2],
};
}
// -------------------------- utils -------------------------- //
function extend( a, b ) {
for ( var prop in b ) {
a[ prop ] = b[ prop ];
}
return a;
}
function getQueryElement( elem ) {
if ( typeof elem == 'string' ) {
elem = document.querySelector( elem );
}
return elem;
}
function hsl2hex( h, s, l ) {
var rgb = hsl2rgb( h, s, l );
return rgb2hex( rgb );
}
// thx jfsiii
// https://github.com/jfsiii/chromath/blob/master/src/static.js#L312
/* eslint-disable max-statements-per-line */
function hsl2rgb( h, s, l ) {
var C = ( 1 - Math.abs( 2 * l - 1 ) ) * s;
var hp = h/60;
var X = C * ( 1 - Math.abs( hp % 2 - 1 ) );
var rgb, m;
switch ( Math.floor( hp ) ) {
case 0: rgb = [ C, X, 0 ]; break;
case 1: rgb = [ X, C, 0 ]; break;
case 2: rgb = [ 0, C, X ]; break;
case 3: rgb = [ 0, X, C ]; break;
case 4: rgb = [ X, 0, C ]; break;
case 5: rgb = [ C, 0, X ]; break;
default: rgb = [ 0, 0, 0 ];
}
m = l - ( C/2 );
rgb = rgb.map( function( v ) {
return v + m;
} );
return rgb;
}
function rgb2hsl( r, g, b ) {
r /= 255; g /= 255; b /= 255;
var M = Math.max( r, g, b );
var m = Math.min( r, g, b );
var C = M - m;
var L = 0.5 * ( M + m );
var S = C === 0 ? 0 : C / ( 1 - Math.abs( 2 * L - 1 ) );
var h;
if ( C === 0 ) {
h = 0; // spec'd as undefined, but usually set to 0
} else if ( M === r ) {
h = ( ( g - b )/C ) % 6;
} else if ( M === g ) {
h = ( ( b - r )/C ) + 2;
} else if ( M === b ) {
h = ( ( r - g )/C ) + 4;
}
var H = 60 * h;
return [ H, parseFloat( S ), parseFloat( L ) ];
}
/* eslint-enable max-statements-per-line */
function rgb2hex( rgb ) {
var hex = rgb.map( function( value ) {
value = Math.round( value * 255 );
var hexNum = value.toString( 16 ).toUpperCase();
// left pad 0
hexNum = hexNum.length < 2 ? '0' + hexNum : hexNum;
return hexNum;
} );
return '#' + hex.join('');
}
// #123456 -> #135
// grab first digit from hex
// not mathematically accurate, but makes for better palette
function roundHex( hex ) {
return '#' + hex[1] + hex[3] + hex[5];
}
// -------------------------- -------------------------- //
return Huebee;
} ) );