Location: A review of cardiac cellular electrophysiology models @ 1c3a018574af / dojo-presentation / js / dojo / dojox / widget / ColorPicker.js

Author:
David Nickerson <david.nickerson@gmail.com>
Date:
2023-04-27 23:14:49-07:00
Desc:
Updates to get things working with OpenCOR 0.7.1
Permanent Source URI:
http://models.cellml.org/workspace/a1/rawfile/1c3a018574af68610e2b95973f32fa831ea3096f/dojo-presentation/js/dojo/dojox/widget/ColorPicker.js

dojo.provide("dojox.widget.ColorPicker");
dojo.experimental("dojox.widget.ColorPicker"); // level: beta

dojo.require("dijit.form._FormWidget");
dojo.require("dojo.dnd.move"); 
dojo.require("dojo.fx"); 

(function(){

	// this ported directly from 0.4 dojo.gfx.colors.hsv, with bugs :)
	// FIXME: use ttrenka's HSB ?
	var _hsv2rgb = function(/* int || Array */h, /* int */s, /* int */v, /* Object? */options){
		//	summary
		//	converts an HSV value set to RGB, ranges depending on optional options object.
		//	patch for options by Matthew Eernisse 	
		if (dojo.isArray(h)) {
			if(s){
				options = s;
			}
			v = h[2] || 0;
			s = h[1] || 0;
			h = h[0] || 0;
		}

		var opt = {
			inputRange:  (options && options.inputRange)  ? options.inputRange : [255, 255, 255],
			outputRange: (options && options.outputRange) ? options.outputRange : 255
		};

	    switch(opt.inputRange[0]) { 
			// 0.0-1.0 
			case 1: h = h * 360; break; 
			// 0-100 
			case 100: h = (h / 100) * 360; break; 
			// 0-360 
			case 360: h = h; break; 
			// 0-255 
			default: h = (h / 255) * 360; 
		} 
		if (h == 360){ h = 0;}

		//	no need to alter if inputRange[1] = 1
		switch(opt.inputRange[1]){
			case 100: s /= 100; break;
			case 255: s /= 255;
		}

		//	no need to alter if inputRange[1] = 1
		switch(opt.inputRange[2]){
			case 100: v /= 100; break;
			case 255: v /= 255;
		}

		var r = null;
		var g = null;
		var b = null;

		if (s == 0){
			// color is on black-and-white center line
			// achromatic: shades of gray
			r = v;
			g = v;
			b = v;
		}else{
			// chromatic color
			var hTemp = h / 60;		// h is now IN [0,6]
			var i = Math.floor(hTemp);	// largest integer <= h
			var f = hTemp - i;		// fractional part of h

			var p = v * (1 - s);
			var q = v * (1 - (s * f));
			var t = v * (1 - (s * (1 - f)));

			switch(i){
				case 0: r = v; g = t; b = p; break;
				case 1: r = q; g = v; b = p; break;
				case 2: r = p; g = v; b = t; break;
				case 3: r = p; g = q; b = v; break;
				case 4: r = t; g = p; b = v; break;
				case 5: r = v; g = p; b = q; break;
			}
		}

		switch(opt.outputRange){
			case 1:
				r = dojo.math.round(r, 2);
				g = dojo.math.round(g, 2);
				b = dojo.math.round(b, 2);
				break;
			case 100:
				r = Math.round(r * 100);
				g = Math.round(g * 100);
				b = Math.round(b * 100);
				break;
			default:
				r = Math.round(r * 255);
				g = Math.round(g * 255);
				b = Math.round(b * 255);
		}
		return [r, g, b];

	};
	
	var webSafeFromHex = function(hex){
		// stub, this is planned later:
		return hex;
	}
		
	dojo.declare("dojox.widget.ColorPicker",
		dijit.form._FormWidget,
		{
		// summary: a HSV color picker - similar to Photoshop picker
		//
		// description: 
		//		Provides an interactive HSV ColorPicker similar to
		//		PhotoShop's color selction tool. This is an enhanced 
		//		version of the default dijit.ColorPalette, though provides
		//		no accessibility.
		// example:
		// |	var picker = new dojox.widget.ColorPicker({
		// |		// a couple of example toggles:
		// |		animatePoint:false,
		// |		showHsv: false,
		// |		webSafe: false,
		// |		showRgb: false 	
		// |	});
		//	
		// example: 
		// | 	<!-- markup: -->
		// | 	<div dojoType="dojox.widget.ColorPicker"></div>
		//
		//
		// showRgb: Boolean
		//	show/update RGB input nodes
		showRgb: true,
	
		// showHsv: Boolean
		//	show/update HSV input nodes
		showHsv: true,
	
		// showHex: Boolean
		//	show/update Hex value field
		showHex: true,

		// webSafe: Boolean
		//	deprecated? or just use a toggle to show/hide that node, too?
		webSafe: true,

		// animatePoint: Boolean
		//	toggle to use slideTo (true) or just place the cursor (false) on click
		animatePoint: true,

		// slideDuration: Integer
		//	time in ms picker node will slide to next location (non-dragging) when animatePoint=true
		slideDuration: 250, 

		// liveUpdate: Boolean
		//		Set to true to fire onChange in an indeterminate way
		liveUpdate: false, 

		_underlay: dojo.moduleUrl("dojox.widget","ColorPicker/images/underlay.png"),
		templatePath: dojo.moduleUrl("dojox.widget","ColorPicker/ColorPicker.html") + "?" + new Date().toString(),

		postCreate: function(){
			// summary: As quickly as we can, set up ie6 alpha-filter support for our
			// 	underlay.  we don't do image handles (done in css), just the 'core' 
			//	of this widget: the underlay. 
			if(dojo.isIE<7){ 
				this.colorUnderlay.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this._underlay+"', sizingMethod='scale')";
				this.colorUnderlay.src = this._blankGif.toString();
			}
			// hide toggle-able nodes:
			if(!this.showRgb){ this.rgbNode.style.display = "none"; }
			if(!this.showHsv){ this.hsvNode.style.display = "none"; }
			if(!this.showHex){ this.hexNode.style.display = "none"; } 
			if(!this.webSafe){ this.safePreviewNode.style.visibility = "hidden"; } 
		},

		startup: function(){

			// this._offset = ((dojo.marginBox(this.cursorNode).w)/2); 
			this._offset = 0; 
			var cmb = dojo.marginBox(this.cursorNode);
			var hmb = dojo.marginBox(this.hueCursorNode);
			this._shift = {
				hue: {
					x: Math.round(hmb.w/2)-1,
					y: Math.round(hmb.h/2)-1
				},
				picker: {
					x: Math.floor(cmb.w / 2),
					y: Math.floor(cmb.h / 2)
				}
			};

			var ox = this._shift.picker.x;
			var oy = this._shift.picker.y;
			this._mover = new dojo.dnd.Moveable(this.cursorNode, {
				mover: dojo.dnd.boxConstrainedMover({ 
					t:0 - oy, 
					l:0 - ox, 
					w:151, h:151
				})
			}); 
			
			this._hueMover = new dojo.dnd.Moveable(this.hueCursorNode, {
				mover: dojo.dnd.boxConstrainedMover({ 
					t:0 - this._shift.hue.y, 
					l:0, w:0, h:150 
				})
			});

			// no dnd/move/move published ... use a timer:
			dojo.subscribe("/dnd/move/stop", dojo.hitch(this, "_clearTimer"));
			dojo.subscribe("/dnd/move/start", dojo.hitch(this, "_setTimer"));

			// ugly scaling calculator.  need a XYslider badly
			this._sc = (1 / dojo.coords(this.colorUnderlay).w);  
			this._hueSc = 255/150;
			
			// initial color
			this._updateColor(); 
		
		},

		_setTimer: function(/* dojo.dnd.Mover */mover){
			// FIXME: should I assume this? focus on mouse down so on mouse up
			dijit.focus(mover.node);
			dojo.setSelectable(this.domNode,false);
			this._timer = setInterval(dojo.hitch(this, "_updateColor"), 45);	
		},
	
		_clearTimer: function(/* dojo.dnd.Mover */mover){
			clearInterval(this._timer);
			this._timer = null;
			this.onChange(this.value);
			dojo.setSelectable(this.domNode,true);
		},

		_setHue: function(/* Decimal */h){
			// summary: sets a natural color background for the 
			// 	underlay image against closest hue value (full saturation) 
			// h: 0..255 

			// this is not a pretty conversion:
			var hue = dojo.colorFromArray(_hsv2rgb(h, 1, 1, { inputRange: 1 })).toHex();
			dojo.style(this.colorUnderlay, "backgroundColor", hue);

		},

		_updateColor: function(){
			// summary: update the previewNode color, and input values [optional]
			
			// all these should be in the [0..150] range
			var _huetop = dojo.style(this.hueCursorNode,"top") + this._shift.hue.y; 
			var _pickertop = dojo.style(this.cursorNode,"top") + this._shift.picker.y;
			var _pickerleft = dojo.style(this.cursorNode,"left") + this._shift.picker.x;
			
			var h = Math.round(255 - (_huetop * this._hueSc));
			var s = Math.round(_pickerleft * this._sc * 100); 
			var v = Math.round(100 - (_pickertop * this._sc ) *100);

			// limit hue calculations to only when it changes
			if(h != this._hue){ this._setHue(h); }

			var rgb = _hsv2rgb(h, s/100, v/100,{ inputRange: 1 }); 
			var hex = dojo.colorFromArray(rgb).toHex();

			this.previewNode.style.backgroundColor = hex;	
			if(this.webSafe){ this.safePreviewNode.style.backgroundColor = webSafeFromHex(hex); }
			if(this.showHex){ this.hexCode.value = hex; }
			if(this.showRgb){
				this.Rval.value = rgb[0];
				this.Gval.value = rgb[1];	
				this.Bval.value = rgb[2];
			}
			if(this.showHsv){
				this.Hval.value = Math.round((h * 360) / 255); // convert to 0..360
				this.Sval.value = s;
				this.Vval.value = v;
			}
			this.value = hex;

			// anytime we muck with the color, fire onChange?
			if ((!this._timer && !arguments[1]) || this.liveUpdate){
				this.setAttribute("value", hex);	
				this.onChange(hex);
			}
		},

		_updatePoints: function(e){
//			update all other values and move points on picker to reflect next values
//			entered in the HEX:
//			console.log('changed? set points to:', e.target.value);
			// not looking forward to the hex->hsv->pixel coordinate reverse calculation
		},

		_setHuePoint: function(/* Event */evt){ 
			// summary: set the hue picker handle on relative y coordinates
			var ypos = evt.layerY - this._shift.hue.y;
			if(this.animatePoint){
				dojo.fx.slideTo({ 
					node: this.hueCursorNode, 
					duration:this.slideDuration,
					top: ypos,
					left: 0,
					onEnd: dojo.hitch(this, "_updateColor", true)
				}).play();
			}else{
				dojo.style(this.hueCursorNode, "top", ypos + "px");
				this._updateColor(false); 
			}
		},

		_setPoint: function(/* Event */evt){
			// summary: set our picker point based on relative x/y coordinates
		//	evt.preventDefault();
			var newTop = evt.layerY - this._shift.picker.y;
			var newLeft = evt.layerX - this._shift.picker.x;
			if(evt){ dijit.focus(evt.target); }

			if(this.animatePoint){
				dojo.fx.slideTo({ 
					node: this.cursorNode, 
					duration:this.slideDuration,
					top: newTop,
					left: newLeft,
					onEnd: dojo.hitch(this,"_updateColor", true)
				}).play();
			}else{
				dojo.style(this.cursorNode, {
					left: newLeft + "px",
					top: newTop + "px"	
				});
				this._updateColor(false); 
			}
		},
		
		_handleKey: function(e){
			// FIXME: not implemented YET
			var keys = dojo.keys;
		}
		
	});

})();