md-rainbow
Version:
Continuation of md-color-picker.
980 lines (805 loc) • 34.2 kB
JavaScript
// Import templates
import mdRainbowTemplate from '../templates/mdRainbow.html';
import mdRainbowContainerTemplate from '../templates/mdRainbowContainer.html';
import mdRainbowDialogTemplate from '../templates/mdRainbowDialog.html';
// Import styles
import '../less/mdRainbow.less';
(function( window, angular, undefined ) {
'use strict';
var dateClick;
var canvasTypes = {
hue: {
getColorByPoint: function( x, y ) {
var imageData = this.getImageData( x, y );
this.setMarkerCenter( y );
var hsl = new tinycolor( {r: imageData[0], g: imageData[1], b: imageData[2] } );
return hsl.toHsl().h;
},
draw: function() {
this.$element.css({'height': this.height + 'px'});
this.canvas.height = this.height;
this.canvas.width = this.height;
// Create gradient
var hueGrd = this.context.createLinearGradient(90, 0.000, 90, this.height);
// Add colors
hueGrd.addColorStop(0.01, 'rgba(255, 0, 0, 1.000)');
hueGrd.addColorStop(0.167, 'rgba(255, 0, 255, 1.000)');
hueGrd.addColorStop(0.333, 'rgba(0, 0, 255, 1.000)');
hueGrd.addColorStop(0.500, 'rgba(0, 255, 255, 1.000)');
hueGrd.addColorStop(0.666, 'rgba(0, 255, 0, 1.000)');
hueGrd.addColorStop(0.828, 'rgba(255, 255, 0, 1.000)');
hueGrd.addColorStop(0.999, 'rgba(255, 0, 0, 1.000)');
// Fill with gradient
this.context.fillStyle = hueGrd;
this.context.fillRect( 0, 0, this.canvas.width, this.height );
}
},
alpha: {
getColorByPoint: function( x, y ) {
var imageData = this.getImageData( x, y );
this.setMarkerCenter( y );
return imageData[3] / 255;
},
draw: function () {
this.$element.css({'height': this.height + 'px'});
this.canvas.height = this.height;
this.canvas.width = this.height;
// Create gradient
var hueGrd = this.context.createLinearGradient(90, 0.000, 90, this.height);
// Add colors
hueGrd.addColorStop(0.01, 'rgba(' + this.currentColor.r + ',' + this.currentColor.g + ',' + this.currentColor.b + ', 1.000)');
hueGrd.addColorStop(0.99, 'rgba(' + this.currentColor.r + ',' + this.currentColor.g + ',' + this.currentColor.b + ', 0.000)');
// Fill with gradient
this.context.fillStyle = hueGrd;
this.context.fillRect( -1, -1, this.canvas.width+2, this.height+2 );
},
extra: function() {
this.$scope.$on('mdRainbow:spectrumColorChange', angular.bind( this, function( e, args ) {
this.currentColor = args.color;
this.draw();
}));
}
},
spectrum: {
getColorByPoint: function( x, y ) {
var imageData = this.getImageData( x, y );
this.setMarkerCenter(x,y);
return {
r: imageData[0],
g: imageData[1],
b: imageData[2]
};
},
draw: function() {
this.canvas.height = this.height;
this.canvas.width = this.height;
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Odd bug prevented selecting min, max ranges from all gradients.
// Start at 0.01, end at 0.99 and stretch it to 1px larger in each direction
// White gradient
var whiteGrd = this.context.createLinearGradient(0, 0, this.canvas.width, 0);
whiteGrd.addColorStop(0.01, 'rgba(255, 255, 255, 1.000)');
whiteGrd.addColorStop(0.99, 'rgba(255, 255, 255, 0.000)');
// Black Gradient
var blackGrd = this.context.createLinearGradient(0, 0, 0, this.canvas.height);
blackGrd.addColorStop(0.01, 'rgba(0, 0, 0, 0.000)');
blackGrd.addColorStop(0.99, 'rgba(0, 0, 0, 1.000)');
// Fill with solid
this.context.fillStyle = 'hsl( ' + this.currentHue + ', 100%, 50%)';
this.context.fillRect( 0, 0, this.canvas.width, this.canvas.height );
// Fill with white
// Odd bug prevented selecting min, max ranges from all gradients
this.context.fillStyle = whiteGrd;
this.context.fillRect( -1, -1, this.canvas.width+2, this.canvas.height+2 );
// Fill with black
// Odd bug prevented selecting min, max ranges from all gradients
this.context.fillStyle = blackGrd;
this.context.fillRect( -1, -1, this.canvas.width+2, this.canvas.height+2 );
},
extra: function() {
this.$scope.$on('mdRainbow:spectrumHueChange', angular.bind( this, function( e, args ) {
this.currentHue = args.hue;
this.draw();
var markerPos = this.getMarkerCenter();
var color = this.getColorByPoint( markerPos.x, markerPos.y );
this.setColor( color );
}));
}
}
};
function GradientCanvasFactory( ) {
return function gradientCanvas( type ) {
var canvas = new GradientCanvas( type, type != 'spectrum' );
canvas = angular.merge( canvas, canvasTypes[type] );
return {
template: '<canvas width="100%" height="100%"></canvas><div class="md-rainbow-marker"></div>',
link: canvas.get,
controller: function() {
// console.log( "mdRainbowAlpha Controller", Date.now() - dateClick );
}
};
}
}
function GradientCanvas( type, restrictX ) {
this.type = type;
this.restrictX = restrictX;
this.offset = {
x: null,
y: null
};
this.height = 255;
this.$scope = null;
this.$element = null;
this.get = angular.bind(this, function( $temp_scope, $temp_element, $temp_attrs ) {
////////////////////////////
// Variables
////////////////////////////
this.$scope = $temp_scope;
this.$element = $temp_element;
this.canvas = this.$element.children()[0];
this.marker = this.$element.children()[1];
this.context = this.canvas.getContext('2d');
this.currentColor = this.$scope.color.toRgb();
this.currentHue = this.$scope.color.toHsv().h;
////////////////////////////
// Watchers, Observes, Events
////////////////////////////
//$scope.$watch( function() { return color.getRgb(); }, hslObserver, true );
this.$element.on('touchstart mousedown', angular.bind(this, this.onMouseDown));
this.$scope.$on('mdRainbow:colorSet', angular.bind( this, this.onColorSet ) );
if ( this.extra ) {
this.extra();
}
////////////////////////////
// init
////////////////////////////
this.draw();
});
//return angular.bind( this, this.get );
}
GradientCanvas.prototype.$window = angular.element( window );
GradientCanvas.prototype.getColorByMouse = function( e ) {
var te = e.touches && e.touches[0];
var pageX = te && te.pageX || e.pageX;
var pageY = te && te.pageY || e.pageY;
var x = Math.round( pageX - this.offset.x );
var y = Math.round( pageY - this.offset.y );
return this.getColorByPoint(x, y);
};
GradientCanvas.prototype.setMarkerCenter = function( x, y ) {
var xOffset = -1 * this.marker.offsetWidth / 2;
var yOffset = -1 * this.marker.offsetHeight / 2;
var xAdjusted, xFinal, yAdjusted, yFinal;
if ( y === undefined ) {
yAdjusted = x + yOffset;
yFinal = Math.round( Math.max( Math.min( this.height-1 + yOffset, yAdjusted), yOffset ) );
xFinal = 0;
} else {
xAdjusted = x + xOffset;
yAdjusted = y + yOffset;
xFinal = Math.floor( Math.max( Math.min( this.height + xOffset, xAdjusted ), xOffset ) );
yFinal = Math.floor( Math.max( Math.min( this.height + yOffset, yAdjusted ), yOffset ) );
// Debug output
// console.log( "Raw: ", x+','+y, "Adjusted: ", xAdjusted + ',' + yAdjusted, "Final: ", xFinal + ',' + yFinal );
}
angular.element(this.marker).css({'left': xFinal + 'px' });
angular.element(this.marker).css({'top': yFinal + 'px'});
};
GradientCanvas.prototype.getMarkerCenter = function() {
var returnObj = {
x: this.marker.offsetLeft + ( Math.floor( this.marker.offsetWidth / 2 ) ),
y: this.marker.offsetTop + ( Math.floor( this.marker.offsetHeight / 2 ) )
};
return returnObj;
};
GradientCanvas.prototype.getImageData = function( x, y ) {
x = Math.max( 0, Math.min( x, this.canvas.width-1 ) );
y = Math.max( 0, Math.min( y, this.canvas.height-1 ) );
var imageData = this.context.getImageData( x, y, 1, 1 ).data;
return imageData;
};
GradientCanvas.prototype.onMouseDown = function( e ) {
// Prevent highlighting
e.preventDefault();
e.stopImmediatePropagation();
this.$scope.previewUnfocus();
this.$element.css({ 'cursor': 'none' });
this.offset.x = this.canvas.getBoundingClientRect().left;
this.offset.y = this.canvas.getBoundingClientRect().top;
var fn = angular.bind( this, function( e ) {
switch( this.type ) {
case 'hue':
var hue = this.getColorByMouse( e );
this.$scope.$broadcast( 'mdRainbow:spectrumHueChange', {hue: hue});
break;
case 'alpha':
var alpha = this.getColorByMouse( e );
this.$scope.color.setAlpha( alpha );
this.$scope.alpha = alpha;
this.$scope.$apply();
break;
case 'spectrum':
var color = this.getColorByMouse( e );
this.setColor( color );
break;
}
});
this.$window.on('touchmove mousemove', fn);
this.$window.one('touchend mouseup', angular.bind(this, function (e) {
this.$window.off('touchmove mousemove', fn);
this.$element.css({ 'cursor': 'crosshair' });
}));
// Set the color
fn( e );
};
GradientCanvas.prototype.setColor = function( color ) {
this.$scope.color._r = color.r;
this.$scope.color._g = color.g;
this.$scope.color._b = color.b;
this.$scope.$apply();
this.$scope.$broadcast('mdRainbow:spectrumColorChange', { color: color });
};
GradientCanvas.prototype.onColorSet = function( e, args ) {
switch( this.type ) {
case 'hue':
var hsv = this.$scope.color.toHsv();
this.setMarkerCenter( this.canvas.height - ( this.canvas.height * ( hsv.h / 360 ) ) );
break;
case 'alpha':
this.currentColor = args.color.toRgb();
this.draw();
var alpha = args.color.getAlpha();
var pos = this.canvas.height - ( this.canvas.height * alpha );
this.setMarkerCenter( pos );
break;
case 'spectrum':
var hsv = args.color.toHsv();
this.currentHue = hsv.h;
this.draw();
var posX = this.canvas.width * hsv.s;
var posY = this.canvas.height - ( this.canvas.height * hsv.v );
this.setMarkerCenter( posX, posY );
break;
}
};
angular.module('mdRainbow', [])
.run(['$templateCache', function ($templateCache) {
//icon resource should not be dependent
//credit to materialdesignicons.com
var shapes = {
'clear': '<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>',
'gradient': '<path d="M11 9h2v2h-2zm-2 2h2v2H9zm4 0h2v2h-2zm2-2h2v2h-2zM7 9h2v2H7zm12-6H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 18H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm2-7h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2H9v-2H7v2H5v-2h2v-2H5V5h14v6z"/>',
'tune': '<path d="M13 21v-2h8v-2h-8v-2h-2v6h2zM3 17v2h6v-2H3z"/><path d="M21 13v-2H11v2h10zM7 9v2H3v2h4v2h2V9H7z"/><path d="M15 9h2V7h4V5h-4V3h-2v6zM3 5v2h10V5H3z"/>',
'view_module': '<path d="M4 11h5V5H4v6z"/><path d="M4 18h5v-6H4v6z"/><path d="M10 18h5v-6h-5v6z"/><path d="M16 18h5v-6h-5v6z"/><path d="M10 11h5V5h-5v6z"/><path d="M16 5v6h5V5h-5z"/>',
'view_headline': '<path d="M4 15h17v-2H4v2z"/><path d="M4 19h17v-2H4v2z"/><path d="M4 11h17V9H4v2z"/><path d="M4 5v2h17V5H4z"/>',
'history': '<path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9z"/><path d="M12 8v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"/>',
'clear_all': '<path d="M5 13h14v-2H5v2zm-2 4h14v-2H3v2zM7 7v2h14V7H7z"/>'
};
for (var i in shapes) {
if (shapes.hasOwnProperty(i)) {
$templateCache.put([i, 'svg'].join('.'),
['<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">', shapes[i], '</svg>'].join(''));
}
}
}])
.factory('mdColorGradientCanvas', GradientCanvasFactory )
.factory('mdRainbowHistory', ['$injector', function( $injector ) {
var history = [];
var strHistory = [];
var $cookies = false;
try {
$cookies = $injector.get('$cookies');
} catch(e) {
}
if ( $cookies ) {
var tmpHistory = $cookies.getObject( 'mdRainbowHistory' ) || [];
for ( var i = 0; i < tmpHistory.length; i++ ) {
history.push( tinycolor( tmpHistory[i] ) );
strHistory.push( tmpHistory[i] );
}
}
var length = 40;
return {
length: function() {
if ( arguments[0] ) {
length = arguments[0];
} else {
return history.length;
}
},
add: function( color ) {
for( var x = 0; x < history.length; x++ ) {
if ( history[x].toRgbString() === color.toRgbString() ) {
history.splice(x, 1);
strHistory.splice(x, 1);
}
}
history.unshift( color );
strHistory.unshift( color.toRgbString() );
if ( history.length > length ) {
history.pop();
strHistory.pop();
}
if ( $cookies ) {
$cookies.putObject('mdRainbowHistory', strHistory );
}
},
get: function() {
return history;
},
reset: function() {
history = [];
strHistory = [];
if ( $cookies ) {
$cookies.putObject('mdRainbowHistory', strHistory );
}
}
};
}])
.directive('mdRainbow', [ '$timeout', 'mdRainbowHistory', function( $timeout, colorHistory ) {
return {
template: mdRainbowTemplate,
// Added required controller ngModel
require: '^ngModel',
scope: {
options: '=mdRainbow',
// Input options
type: '@',
label: '@?',
icon: '@?',
random: '@?',
default: '@?',
// Dialog Options
openOnInput: '=?',
hasBackdrop: '=?',
clickOutsideToClose: '=?',
skipHide: '=?',
preserveScope: '=?',
multiple: '=?',
// Advanced options
okText: '@?',
cancelText: '@?',
mdColorClearButton: '=?',
mdColorPreview: '=?',
mdColorAlphaChannel: '=?',
mdColorSpectrum: '=?',
mdColorSliders: '=?',
mdColorGenericPalette: '=?',
mdColorMaterialPalette: '=?',
mdColorHistory: '=?',
mdColorHex: '=?',
mdColorRgb: '=?',
mdColorHsl: '=?',
mdColorDefaultTab: '=?'
},
controller: ['$scope', '$element', '$attrs', '$mdDialog', '$mdRainbow', function( $scope, $element, $attrs, $mdDialog, $mdRainbow ) {
var didJustClose = false;
var defaultOkText = 'Select';
var defaultCancelText = 'Cancel';
// Merge Options Object with scope. Scope will take precedence much like css vs style attribute.
if ( $scope.options !== undefined ) {
for ( var opt in $scope.options ) {
if ( $scope.options.hasOwnProperty( opt ) ) {
var scopeKey;
//if ( $scope.hasOwnProperty( opt ) ) { // Removing this because optional scope properties are not added to the scope.
scopeKey = opt;
//} else
if ( $scope.hasOwnProperty( 'mdColor' + opt.slice(0,1).toUpperCase() + opt.slice(1) ) ) {
scopeKey = 'mdColor' + opt.slice(0,1).toUpperCase() + opt.slice(1);
}
if ( scopeKey && ( $scope[scopeKey] === undefined || $scope[scopeKey] === '' ) ) {
$scope[scopeKey] = $scope.options[opt];
}
}
}
}
// Get ngModelController from the current element
var ngModel = $element.controller('ngModel');
// Quick function for updating the local 'value' on scope
var updateValue = function(val) {
$scope.value = val || ngModel.$viewValue || '';
};
// Defaults
// Everything is enabled by default.
$scope.defaultOkText = defaultOkText;
$scope.defaultCancelText = defaultCancelText;
$scope.okText = $scope.okText === undefined ? defaultOkText : $scope.okText;
$scope.cancelText = $scope.cancelText === undefined ? defaultCancelText : $scope.cancelText;
$scope.mdColorClearButton = $scope.mdColorClearButton === undefined ? true : $scope.mdColorClearButton;
$scope.mdColorPreview = $scope.mdColorPreview === undefined ? true : $scope.mdColorPreview;
$scope.mdColorAlphaChannel = $scope.mdColorAlphaChannel === undefined ? true : $scope.mdColorAlphaChannel;
$scope.mdColorSpectrum = $scope.mdColorSpectrum === undefined ? true : $scope.mdColorSpectrum;
$scope.mdColorSliders = $scope.mdColorSliders === undefined ? true : $scope.mdColorSliders;
$scope.mdColorGenericPalette = $scope.mdColorGenericPalette === undefined ? true : $scope.mdColorGenericPalette;
$scope.mdColorMaterialPalette = $scope.mdColorMaterialPalette === undefined ? true : $scope.mdColorMaterialPalette;
$scope.mdColorHistory = $scope.mdColorHistory === undefined ? true : $scope.mdColorHistory;
$scope.mdColorHex = $scope.mdColorHex === undefined ? true : $scope.mdColorHex;
$scope.mdColorRgb = $scope.mdColorRgb === undefined ? true : $scope.mdColorRgb;
$scope.mdColorHsl = $scope.mdColorHsl === undefined ? true : $scope.mdColorHsl;
// Set the starting value
updateValue();
// Keep an eye on changes
$scope.$watch(function() {
return ngModel.$modelValue;
},function(newVal) {
updateValue(newVal);
});
// Watch for updates to value and set them on the model
$scope.$watch('value',function(newVal,oldVal) {
if (newVal !== '' && typeof newVal !== 'undefined' && newVal && newVal !== oldVal) {
ngModel.$setViewValue(newVal);
}
});
// The only other ngModel changes
$scope.clearValue = function clearValue() {
ngModel.$setViewValue('');
ngModel.$render();
};
$scope.showColorPicker = function showColorPicker($event) {
if ( didJustClose ) {
return;
}
// dateClick = Date.now();
// console.log( "CLICK OPEN", dateClick, $scope );
$mdRainbow.show({
value: $scope.value,
defaultValue: $scope.default,
random: $scope.random,
clickOutsideToClose: $scope.clickOutsideToClose,
hasBackdrop: $scope.hasBackdrop,
skipHide: $scope.skipHide,
preserveScope: $scope.preserveScope,
multiple: $scope.multiple,
okText : $scope.okText,
cancelText : $scope.cancelText,
mdColorAlphaChannel: $scope.mdColorAlphaChannel,
mdColorSpectrum: $scope.mdColorSpectrum,
mdColorSliders: $scope.mdColorSliders,
mdColorGenericPalette: $scope.mdColorGenericPalette,
mdColorMaterialPalette: $scope.mdColorMaterialPalette,
mdColorHistory: $scope.mdColorHistory,
mdColorHex: $scope.mdColorHex,
mdColorRgb: $scope.mdColorRgb,
mdColorHsl: $scope.mdColorHsl,
mdColorDefaultTab: $scope.mdColorDefaultTab,
$event: $event,
}).then(function( color ) {
$scope.value = color;
});
};
}],
compile: function( element, attrs ) {
//attrs.value = attrs.value || "#ff0000";
attrs.type = attrs.type !== undefined ? attrs.type : 0;
}
};
}])
.directive( 'mdRainbowContainer', ['$compile','$timeout','$mdColorPalette','mdRainbowHistory', function( $compile, $timeout, $mdColorPalette, colorHistory ) {
return {
template: mdRainbowContainerTemplate,
scope: {
value: '=?',
default: '@',
random: '@',
ok: '=?',
mdColorAlphaChannel: '=',
mdColorSpectrum: '=',
mdColorSliders: '=',
mdColorGenericPalette: '=',
mdColorMaterialPalette: '=',
mdColorHistory: '=',
mdColorHex: '=',
mdColorRgb: '=',
mdColorHsl: '=',
mdColorDefaultTab: '='
},
controller: function( $scope, $element, $attrs ) {
// console.log( "mdRainbowContainer Controller", Date.now() - dateClick, $scope );
function getTabIndex( tab ) {
var index = 0;
if ( tab && typeof( tab ) === 'string' ) {
/* DOM isn't fast enough for this
var tabs = $element[0].querySelector('.md-rainbow-colors').getElementsByTagName( 'md-tab' );
console.log( tabs.length );
*/
var tabName = 'mdColor' + tab.slice(0,1).toUpperCase() + tab.slice(1);
var tabs = ['mdColorSpectrum', 'mdColorSliders', 'mdColorGenericPalette', 'mdColorMaterialPalette', 'mdColorHistory'];
for ( var x = 0; x < tabs.length; x++ ) {
//console.log( tabs[x]('ng-if') );
//if ( tabs[x].getAttribute('ng-if') == tabName ) {
if ( tabs[x] == tabName ) {
if ( $scope[tabName] ) {
index = x;
break;
}
}
}
} else if ( tab && typeof ( tab ) === 'number') {
index = tab;
}
return index;
}
///////////////////////////////////
// Variables
///////////////////////////////////
var container = angular.element( $element[0].querySelector('.md-rainbow-container') );
var resultSpan = angular.element( container[0].querySelector('.md-rainbow-result') );
var previewInput = angular.element( $element[0].querySelector('.md-rainbow-preview-input') );
var outputFn = [
'toHexString',
'toRgbString',
'toHslString'
];
$scope.default = $scope.default ? $scope.default : $scope.random ? tinycolor.random() : 'rgb(255,255,255)';
if ( $scope.value.search('#') >= 0 ) {
$scope.type = 0;
} else if ( $scope.value.search('rgb') >= 0 ) {
$scope.type = 1;
} else if ( $scope.value.search('hsl') >= 0 ) {
$scope.type = 2;
}
$scope.color = new tinycolor($scope.value || $scope.default); // Set initial color
$scope.alpha = $scope.color.getAlpha();
$scope.history = colorHistory;
$scope.materialFamily = [];
$scope.whichPane = getTabIndex( $scope.mdColorDefaultTab );
$scope.inputFocus = false;
// Colors for the palette screen
///////////////////////////////////
var steps = 9;
var freq = 2*Math.PI/steps;
$scope.palette = [
["rgb(255, 204, 204)","rgb(255, 230, 204)","rgb(255, 255, 204)","rgb(204, 255, 204)","rgb(204, 255, 230)","rgb(204, 255, 255)","rgb(204, 230, 255)","rgb(204, 204, 255)","rgb(230, 204, 255)","rgb(255, 204, 255)"],
["rgb(255, 153, 153)","rgb(255, 204, 153)","rgb(255, 255, 153)","rgb(153, 255, 153)","rgb(153, 255, 204)","rgb(153, 255, 255)","rgb(153, 204, 255)","rgb(153, 153, 255)","rgb(204, 153, 255)","rgb(255, 153, 255)"],
["rgb(255, 102, 102)","rgb(255, 179, 102)","rgb(255, 255, 102)","rgb(102, 255, 102)","rgb(102, 255, 179)","rgb(102, 255, 255)","rgb(102, 179, 255)","rgb(102, 102, 255)","rgb(179, 102, 255)","rgb(255, 102, 255)"],
["rgb(255, 51, 51)","rgb(255, 153, 51)","rgb(255, 255, 51)","rgb(51, 255, 51)","rgb(51, 255, 153)","rgb(51, 255, 255)","rgb(51, 153, 255)","rgb(51, 51, 255)","rgb(153, 51, 255)","rgb(255, 51, 255)"],
["rgb(255, 0, 0)","rgb(255, 128, 0)","rgb(255, 255, 0)","rgb(0, 255, 0)","rgb(0, 255, 128)","rgb(0, 255, 255)","rgb(0, 128, 255)","rgb(0, 0, 255)","rgb(128, 0, 255)","rgb(255, 0, 255)"],
["rgb(245, 0, 0)","rgb(245, 123, 0)","rgb(245, 245, 0)","rgb(0, 245, 0)","rgb(0, 245, 123)","rgb(0, 245, 245)","rgb(0, 123, 245)","rgb(0, 0, 245)","rgb(123, 0, 245)","rgb(245, 0, 245)"],
["rgb(214, 0, 0)","rgb(214, 108, 0)","rgb(214, 214, 0)","rgb(0, 214, 0)","rgb(0, 214, 108)","rgb(0, 214, 214)","rgb(0, 108, 214)","rgb(0, 0, 214)","rgb(108, 0, 214)","rgb(214, 0, 214)"],
["rgb(163, 0, 0)","rgb(163, 82, 0)","rgb(163, 163, 0)","rgb(0, 163, 0)","rgb(0, 163, 82)","rgb(0, 163, 163)","rgb(0, 82, 163)","rgb(0, 0, 163)","rgb(82, 0, 163)","rgb(163, 0, 163)"],
["rgb(92, 0, 0)","rgb(92, 46, 0)","rgb(92, 92, 0)","rgb(0, 92, 0)","rgb(0, 92, 46)","rgb(0, 92, 92)","rgb(0, 46, 92)","rgb(0, 0, 92)","rgb(46, 0, 92)","rgb(92, 0, 92)"],
["rgb(255, 255, 255)","rgb(205, 205, 205)","rgb(178, 178, 178)","rgb(153, 153, 153)","rgb(127, 127, 127)","rgb(102, 102, 102)","rgb(76, 76, 76)","rgb(51, 51, 51)","rgb(25, 25, 25)","rgb(0, 0, 0)"]
];
$scope.materialPalette = $mdColorPalette;
///////////////////////////////////
// Functions
///////////////////////////////////
$scope.isDark = function isDark( color ) {
if ( angular.isArray( color ) ) {
return tinycolor( {r: color[0], g: color[1], b: color[2] }).isDark();
} else {
return tinycolor( color ).isDark();
}
};
$scope.previewFocus = function() {
$scope.inputFocus = true;
$timeout( function() {
previewInput[0].setSelectionRange(0, previewInput[0].value.length);
});
};
$scope.previewUnfocus = function() {
$scope.inputFocus = false;
previewInput[0].blur();
};
$scope.previewBlur = function() {
$scope.inputFocus = false;
$scope.setValue();
};
$scope.previewKeyDown = function( $event ) {
if ( $event.keyCode == 13 ) {
$scope.ok && $scope.ok();
}
};
$scope.setPaletteColor = function( event ) {
$timeout( function() {
$scope.color = tinycolor( event.target.style.backgroundColor );
});
};
$scope.setValue = function setValue() {
// Set the value if available
if ( $scope.color && $scope.color && outputFn[$scope.type] && $scope.color.toRgbString() !== 'rgba(0, 0, 0, 0)' ) {
$scope.value = $scope.color[outputFn[$scope.type]]();
}
};
$scope.changeValue = function changeValue() {
$scope.color = tinycolor( $scope.value );
$scope.$broadcast('mdRainbow:colorSet', { color: $scope.color });
};
///////////////////////////////////
// Watches and Events
///////////////////////////////////
$scope.$watch( 'color._a', function( newValue ) {
$scope.color.setAlpha( newValue );
}, true);
$scope.$watch( 'whichPane', function( newValue ) {
// 0 - spectrum selector
// 1 - sliders
// 2 - palette
$scope.$broadcast('mdRainbow:colorSet', {color: $scope.color });
});
$scope.$watch( 'type', function() {
previewInput.removeClass('switch');
$timeout(function() {
previewInput.addClass('switch');
});
});
$scope.$watchGroup(['color.toRgbString()', 'type'], function( newValue ) {
if ( !$scope.inputFocus ) {
$scope.setValue();
}
});
///////////////////////////////////
// INIT
// Let all the other directives initialize
///////////////////////////////////
// console.log( "mdRainbowContainer Controller PRE Timeout", Date.now() - dateClick );
$timeout( function() {
// console.log( "mdRainbowContainer Controller Timeout", Date.now() - dateClick );
$scope.$broadcast('mdRainbow:colorSet', { color: $scope.color });
previewInput.focus();
$scope.previewFocus();
});
},
link: function( scope, element, attrs ) {
var tabs = element[0].getElementsByTagName( 'md-tab' );
/*
Replicating these structure without ng-repeats
<div ng-repeat="row in palette track by $index" flex="15" layout-align="space-between" layout="row" layout-fill>
<div ng-repeat="col in row track by $index" flex="10" style="height: 25.5px;" ng-style="{'background': col};" ng-click="setPaletteColor($event)"></div>
</div>
<div ng-repeat="(key, value) in materialColors">
<div ng-style="{'background': 'rgb('+value['500'].value[0]+','+value['500'].value[1]+','+value['500'].value[2]+')', height: '75px'}" class="md-rainbow-material-title" ng-class="{'dark': isDark( value['500'].value )}" ng-click="setPaletteColor($event)">
<span>{{key}}</span>
</div>
<div ng-repeat="(label, color) in value track by $index" ng-style="{'background': 'rgb('+color.value[0]+','+color.value[1]+','+color.value[2]+')', height: '33px'}" class="md-rainbow-with-label" ng-class="{'dark': isDark( color.value )}" ng-click="setPaletteColor($event)">
<span>{{label}}</span>
</div>
</div>
*/
$timeout(function() {
createDOM();
});
function createDOM() {
var paletteContainer = angular.element( element[0].querySelector('.md-rainbow-palette') );
var materialContainer = angular.element( element[0].querySelector('.md-rainbow-material-palette') );
var paletteRow = angular.element('<div class="flex-15 layout-fill layout-row layout-align-space-between" layout-align="space-between" layout="row" layout-fill"></div>');
var paletteCell = angular.element('<div class="flex-10"></div>');
var materialTitle = angular.element('<div class="md-rainbow-material-title"></div>');
var materialRow = angular.element('<div class="md-rainbow-with-label"></div>');
angular.forEach(scope.palette, function( value, key ) {
var row = paletteRow.clone();
angular.forEach( value, function( color ) {
var cell = paletteCell.clone();
cell.css({
height: '25.5px',
backgroundColor: color
});
cell.bind('click', scope.setPaletteColor );
row.append( cell );
});
paletteContainer.append( row );
});
angular.forEach(scope.materialPalette, function( value, key ) {
var title = materialTitle.clone();
title.html('<span>'+key.replace('-',' ')+'</span>');
title.css({
height: '75px',
backgroundColor: 'rgb('+value['500'].value[0]+','+value['500'].value[1]+','+value['500'].value[2]+')'
});
if ( scope.isDark(value['500'].value) ) {
title.addClass('dark');
}
materialContainer.append( title );
angular.forEach( value, function( color, label ) {
var row = materialRow.clone();
row.css({
height: '33px',
backgroundColor: 'rgb('+color.value[0]+','+color.value[1]+','+color.value[2]+')'
});
if ( scope.isDark(color.value) ) {
row.addClass('dark');
}
row.html('<span>'+label+'</span>');
row.bind('click', scope.setPaletteColor );
materialContainer.append( row );
});
});
}
}
};
}])
.directive( 'mdRainbowHue', ['mdColorGradientCanvas', function( mdColorGradientCanvas ) { return new mdColorGradientCanvas('hue'); }])
.directive( 'mdRainbowAlpha', ['mdColorGradientCanvas', function( mdColorGradientCanvas ) { return new mdColorGradientCanvas('alpha'); }])
.directive( 'mdRainbowSpectrum', ['mdColorGradientCanvas', function( mdColorGradientCanvas ) { return new mdColorGradientCanvas('spectrum'); }])
.factory('$mdRainbow', ['$q', '$mdDialog', 'mdRainbowHistory', function ($q, $mdDialog, colorHistory) {
var dialog;
return {
show: function (options)
{
if ( options === undefined ) {
options = {};
}
//console.log( 'DIALOG OPTIONS', options );
// Defaults
// Dialog Properties
options.hasBackdrop = options.hasBackdrop === undefined ? true : options.hasBackdrop;
options.clickOutsideToClose = options.clickOutsideToClose === undefined ? true : options.clickOutsideToClose;
options.defaultValue = options.defaultValue === undefined ? '#FFFFFF' : options.defaultValue;
options.focusOnOpen = options.focusOnOpen === undefined ? false : options.focusOnOpen;
options.preserveScope = options.preserveScope === undefined ? true : options.preserveScope;
options.skipHide = options.skipHide === undefined ? true : options.skipHide;
options.multiple = options.multiple === undefined ? true : options.multiple;
// mdRainbow Properties
options.okText = options.okText === undefined ? 'Select' : options.okText;
options.cancelText = options.cancelText === undefined ? 'Cancel' : options.cancelText;
options.mdColorAlphaChannel = options.mdColorAlphaChannel === undefined ? false : options.mdColorAlphaChannel;
options.mdColorSpectrum = options.mdColorSpectrum === undefined ? true : options.mdColorSpectrum;
options.mdColorSliders = options.mdColorSliders === undefined ? true : options.mdColorSliders;
options.mdColorGenericPalette = options.mdColorGenericPalette === undefined ? true : options.mdColorGenericPalette;
options.mdColorMaterialPalette = options.mdColorMaterialPalette === undefined ? true : options.mdColorMaterialPalette;
options.mdColorHistory = options.mdColorHistory === undefined ? true : options.mdColorHistory;
options.mdColorRgb = options.mdColorRgb === undefined ? true : options.mdColorRgb;
options.mdColorHsl = options.mdColorHsl === undefined ? true : options.mdColorHsl;
options.mdColorHex = ((options.mdColorHex === undefined) || (!options.mdColorRgb && !options.mdColorHsl)) ? true : options.mdColorHex;
options.mdColorAlphaChannel = (!options.mdColorRgb && !options.mdColorHsl) ? false : options.mdColorAlphaChannel;
dialog = $mdDialog.show({
template: mdRainbowDialogTemplate,
hasBackdrop: options.hasBackdrop,
clickOutsideToClose: options.clickOutsideToClose,
multiple: options.multiple,
controller: ['$scope', 'options', function( $scope, options ) {
//console.log( "DIALOG CONTROLLER OPEN", Date.now() - dateClick );
$scope.close = function close()
{
$mdDialog.cancel();
};
$scope.ok = function ok()
{
$mdDialog.hide( $scope.value );
};
$scope.hide = $scope.ok;
$scope.value = options.value;
$scope.default = options.defaultValue;
$scope.random = options.random;
$scope.okText = options.okText;
$scope.cancelText = options.cancelText;
$scope.mdColorAlphaChannel = options.mdColorAlphaChannel;
$scope.mdColorSpectrum = options.mdColorSpectrum;
$scope.mdColorSliders = options.mdColorSliders;
$scope.mdColorGenericPalette = options.mdColorGenericPalette;
$scope.mdColorMaterialPalette = options.mdColorMaterialPalette;
$scope.mdColorHistory = options.mdColorHistory;
$scope.mdColorHex = options.mdColorHex;
$scope.mdColorRgb = options.mdColorRgb;
$scope.mdColorHsl = options.mdColorHsl;
$scope.mdColorDefaultTab = options.mdColorDefaultTab;
}],
locals: {
options: options,
},
preserveScope: options.preserveScope,
skipHide: options.skipHide,
targetEvent: options.$event,
focusOnOpen: options.focusOnOpen,
autoWrap: false,
onShowing: function() {
// console.log( "DIALOG OPEN START", Date.now() - dateClick );
},
onComplete: function() {
// console.log( "DIALOG OPEN COMPLETE", Date.now() - dateClick );
}
});
dialog.then(function (value) {
colorHistory.add(new tinycolor(value));
}, function () { });
return dialog;
},
hide: function() {
return dialog.hide();
},
cancel: function() {
return dialog.cancel();
}
};
}]);
})( window, window.angular );