Skip to content

Commit

Permalink
Factored out SpectrumSlider and added FrequencySlider, see #371
Browse files Browse the repository at this point in the history
  • Loading branch information
samreid committed Apr 13, 2018
1 parent 8cf5b43 commit 91cee71
Show file tree
Hide file tree
Showing 8 changed files with 619 additions and 423 deletions.
60 changes: 60 additions & 0 deletions js/AbstractSpectrumNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2014-2017, University of Colorado Boulder

/**
* AbstractSpectrumNode displays a rectangle of the visible spectrum.
*
* @author Chris Malley (PixelZoom, Inc.)
*/
define( function( require ) {
'use strict';

// modules
var Bounds2 = require( 'DOT/Bounds2' );
var Dimension2 = require( 'DOT/Dimension2' );
var Image = require( 'SCENERY/nodes/Image' );
var inherit = require( 'PHET_CORE/inherit' );
var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
var Util = require( 'DOT/Util' );

/**
* Slider track that displays the visible spectrum.
*
* @param {Object} [options]
* @constructor
*/
function AbstractSpectrumNode( options ) {

options = _.extend( {
size: new Dimension2( 150, 30 ),
minValue: 0,
maxValue: 1,
valueToColor: null // {function} - required, maps value => Color
}, options );

// validate values
assert && assert( options.minValue < options.maxValue, 'min should be less than max' );
assert && assert( !!options.valueToColor, 'valueToColor is required' );

// Draw the spectrum directly to a canvas, to improve performance.
var canvas = document.createElement( 'canvas' );
var context = canvas.getContext( '2d' );
canvas.width = options.size.width;
canvas.height = options.size.height;

// map position to wavelength
for ( var i = 0; i < options.size.width; i++ ) {
var value = Util.clamp( Util.linear( 0, options.size.width, options.minValue, options.maxValue, i ), options.minValue, options.maxValue );
context.fillStyle = options.valueToColor( value ).toCSS();
context.fillRect( i, 0, 1, options.size.height );
}

Image.call( this, canvas.toDataURL(), options );

// since the Image's bounds aren't immediately computed, we override it here
this.setLocalBounds( new Bounds2( 0, 0, options.size.width, options.size.height ) );
}

sceneryPhet.register( 'AbstractSpectrumNode', AbstractSpectrumNode );

return inherit( Image, AbstractSpectrumNode );
} );
54 changes: 54 additions & 0 deletions js/FrequencySlider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2018, University of Colorado Boulder

/**
* Slider that shows a spectrum of colors for selecting a frequency.
*
* @author Sam Reid (PhET Interactive Simulations)
*/
define( function( require ) {
'use strict';

// modules
var inherit = require( 'PHET_CORE/inherit' );
var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
var SpectrumSlider = require( 'SCENERY_PHET/SpectrumSlider' );
var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
var Util = require( 'DOT/Util' );
var VisibleColor = require( 'SCENERY_PHET/VisibleColor' );

// strings
var frequencySliderPattern0Frequency1UnitsString = require( 'string!SCENERY_PHET/FrequencySlider.pattern_0frequency_1units' );
var unitsTHzString = require( 'string!SCENERY_PHET/unitsTHz' );

/**
* @param {Property.<number>} wavelengthProperty - wavelength, in nm
* @param {Object} [options]
* @constructor
*/
function FrequencySlider( wavelengthProperty, options ) {

// options that are specific to this type
options = _.extend( {

minFrequency: VisibleColor.MIN_FREQUENCY,
maxFrequency: VisibleColor.MAX_FREQUENCY,
valueToString: function( value ) {
return StringUtils.format( frequencySliderPattern0Frequency1UnitsString, Util.toFixed( value / 1E12, 0 ), unitsTHzString );
},
valueToColor: function( value ) {
return VisibleColor.frequencyToColor( value );
}
}, options );
assert && assert( typeof options.minValue === 'undefined', 'minValue is supplied by FrequencySlider' );
assert && assert( typeof options.maxValue === 'undefined', 'maxValue is supplied by FrequencySlider' );
assert && assert( typeof options.createTrackNode === 'undefined', 'createTrackNode is supplied by FrequencySlider' );
options.minValue = options.minFrequency;
options.maxValue = options.maxFrequency;

SpectrumSlider.call( this, wavelengthProperty, options );
}

sceneryPhet.register( 'FrequencySlider', FrequencySlider );

return inherit( SpectrumSlider, FrequencySlider );
} );
41 changes: 16 additions & 25 deletions js/SpectrumNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,49 @@
/**
* SpectrumNode displays a rectangle of the visible spectrum.
*
* TODO: Rename this to WavelengthSpectrumNode, and rename AbstractSpectrumNode to SpectrumNode
*
* @author Chris Malley (PixelZoom, Inc.)
*/
define( function( require ) {
'use strict';

// modules
var Bounds2 = require( 'DOT/Bounds2' );
var Dimension2 = require( 'DOT/Dimension2' );
var Image = require( 'SCENERY/nodes/Image' );
var inherit = require( 'PHET_CORE/inherit' );
var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
var Util = require( 'DOT/Util' );
var VisibleColor = require( 'SCENERY_PHET/VisibleColor' );
var AbstractSpectrumNode = require( 'SCENERY_PHET/AbstractSpectrumNode' );

/**
* Slider track that displays the visible spectrum.
* Slider track that displays the visible spectrum of light.
*
* @param {Object} [options]
* @constructor
*/
function SpectrumNode( options ) {

options = _.extend( {
size: new Dimension2( 150, 30 ),
minWavelength: VisibleColor.MIN_WAVELENGTH,
maxWavelength: VisibleColor.MAX_WAVELENGTH
}, options );

// validate wavelengths
// validation
assert && assert( options.minWavelength < options.maxWavelength );
assert && assert( options.minWavelength >= VisibleColor.MIN_WAVELENGTH && options.minWavelength <= VisibleColor.MAX_WAVELENGTH );
assert && assert( options.maxWavelength >= VisibleColor.MIN_WAVELENGTH && options.maxWavelength <= VisibleColor.MAX_WAVELENGTH );
assert && assert( typeof options.minValue === 'undefined', 'minValue is supplied by WavelengthSlider' );
assert && assert( typeof options.maxValue === 'undefined', 'maxValue is supplied by WavelengthSlider' );

options.minValue = options.minWavelength;
options.maxValue = options.maxWavelength;
options.valueToColor = function( value ) {
return VisibleColor.wavelengthToColor( value );
};

// Draw the spectrum directly to a canvas, to improve performance.
var canvas = document.createElement( 'canvas' );
var context = canvas.getContext( '2d' );
canvas.width = options.size.width;
canvas.height = options.size.height;
for ( var i = 0; i < options.size.width; i++ ) {
// map position to wavelength
var wavelength = Util.clamp( Util.linear( 0, options.size.width, options.minWavelength, options.maxWavelength, i ), options.minWavelength, options.maxWavelength );
context.fillStyle = VisibleColor.wavelengthToColor( wavelength ).toCSS();
context.fillRect( i, 0, 1, options.size.height );
}

Image.call( this, canvas.toDataURL(), options );

// since the Image's bounds aren't immediately computed, we override it here
this.setLocalBounds( new Bounds2( 0, 0, options.size.width, options.size.height ) );
AbstractSpectrumNode.call( this, options );
}

sceneryPhet.register( 'SpectrumNode', SpectrumNode );

return inherit( Image, SpectrumNode );
} );
return inherit( AbstractSpectrumNode, SpectrumNode );
} );
Loading

0 comments on commit 91cee71

Please sign in to comment.