ColorMapEditorWidget

A widget for modifying colormaps. Allows control of opacity transfer function, range and preset. This widget displays the colormap information passed in and provides controls for editing. However the controls will not work unless the callbacks they trigger set the correct properties on the widget. This is so that external events (such as changing which colormap is being edited) are free to update these properties as well.

Properties

currentOpacityPoints

This property is the current point values of the opacity transfer function. It should be a list of objects of the form { x: dataValue, y: opacity} where dataValue and opacity are in the interval [0, 1]. The dataValue is mapped into the interval [rangeMin, rangeMax] for display, but in this property should always be in the interal [0, 1] To properly update the widget it should be set by the function onOpacityTransferFunctionChanged.

currentPreset

The name of the current lookup table preset. See the presets property for valid names. To properly update the widget it should be set by the function onPresetChanged.

dataRangeMin

The lowest value that can be set for the range minimum.

dataRangeMax

The highest value that can be set for the range maximum.

presets

This is an object with the names an images of each lookup table preset. presets['abc'] should be the image for the preset with name 'abc'.

rangeMin

The current minimum range of the colorMap. To properly update the widget, it should be set by onRangeEdited, onScaleRangeToCurrent and onScaleRangeOverTime.

rangeMax

The current maximum range of the colorMap. To properly update the widget, it should be set by onRangeEdited, onScaleRangeToCurrent and onScaleRangeOverTime.

onOpacityTransferFunctionChanged

This function will be called whenever the opacity transfer function changes. It will be passed a list of objects of the form { x: dataValue, y: opacity } where dataValue is a number in the current range of the colorMap and opacity is a floating point value in the interval [0, 1]. Should update currentOpacityPoints.

onPresetChanged

This function will be called when the user chooses a new preset to use. It will be passed the name of the new preset as a string. Should update onPresetChanged.

onRangeEdited

This function will be called when the user manually edits the range of the dataset. It will be passed an array with two values: the new min and max of the range. Should update rangeMin and rangeMax.

onScaleRangeToCurrent

This function will be called when the user presses the Scale Range to Dataset button. Should update rangeMin and rangeMax.

onScaleRangeOverTime

This function will be called when the user presses the Scale Range to Data Over Time button. Should update rangeMin and rangeMax.

pieceWiseHeight

The height of the piecewise function (opacity map) editor’s canvas. See the height property of the PieceWiseFunctionEditorWidget.

pieceWiseWidth

The width of the piecewise function (opacity map) editor’s canvas. See the width property of the PieceWiseFunctionEditorWidget.

Source

index.js
import React from 'react';
import PropTypes from 'prop-types';

import style from 'PVWStyle/ReactWidgets/ColorMapEditorWidget.mcss';

import SvgIconWidget from '../SvgIconWidget';
import PieceWiseFunctionEditorWidget from '../PieceWiseFunctionEditorWidget';
import PresetListWidget from '../PresetListWidget';

import paletteIcon from '../../../../svg/colors/Palette.svg';
import opacityIcon from '../../../../svg/colors/Opacity.svg';
import timeIcon from '../../../../svg/colors/Time.svg';
import datasetIcon from '../../../../svg/colors/DataSet.svg';

export default class ColorMapEditorWidget extends React.Component {
constructor(props) {
super(props);
this.state = {
showOpacityControls: false,
showPresetSelection: false,
};

// Bind callback
this.onOpacityTransferFunctionChanged = this.onOpacityTransferFunctionChanged.bind(
this
);
this.toggleShowOpacityControls = this.toggleShowOpacityControls.bind(this);
this.toggleShowPresetSelection = this.toggleShowPresetSelection.bind(this);
this.rangeMinChanged = this.rangeMinChanged.bind(this);
this.rangeMaxChanged = this.rangeMaxChanged.bind(this);
this.presetChanged = this.presetChanged.bind(this);
}

onOpacityTransferFunctionChanged(newPoints) {
if (this.props.onOpacityTransferFunctionChanged) {
this.props.onOpacityTransferFunctionChanged(newPoints);
}
}

toggleShowOpacityControls() {
const newState = { showOpacityControls: !this.state.showOpacityControls };
if (this.state.showPresetSelection && newState.showOpacityControls) {
newState.showPresetSelection = false;
}
this.setState(newState);
}

toggleShowPresetSelection() {
const newState = { showPresetSelection: !this.state.showPresetSelection };
if (this.state.showOpacityControls && newState.showPresetSelection) {
newState.showOpacityControls = false;
}
this.setState(newState);
}

rangeMinChanged(e) {
const newMin = parseFloat(e.target.value);
if (this.props.onRangeEdited) {
this.props.onRangeEdited([newMin, this.props.rangeMax]);
}
}

rangeMaxChanged(e) {
const newMax = parseFloat(e.target.value);
if (this.props.onRangeEdited) {
this.props.onRangeEdited([this.props.rangeMin, newMax]);
}
}

presetChanged(name) {
if (this.props.onPresetChanged) {
this.props.onPresetChanged(name);
}
}

render() {
const presets = this.props.presets;
const name = this.props.currentPreset;
return (
<div className={style.colormapeditor}>
<div className={style.mainControls}>
<SvgIconWidget
className={style.svgIcon}
icon={opacityIcon}
onClick={this.toggleShowOpacityControls}
/>
<img
className={style.presetImage}
src={`data:image/png;base64,${presets[name]}`}
alt={this.props.currentPreset}
/>
<SvgIconWidget
className={style.svgIcon}
icon={paletteIcon}
onClick={this.toggleShowPresetSelection}
/>
</div>
<div className={style.rangeControls}>
<input
className={style.minRangeInput}
type="number"
step="any"
min={this.props.dataRangeMin}
max={this.props.dataRangeMax}
value={this.props.rangeMin}
onChange={this.rangeMinChanged}
/>
<div className={style.rangeResetButtons}>
<SvgIconWidget
className={style.svgIcon}
icon={timeIcon}
onClick={this.props.onScaleRangeOverTime}
/>
<SvgIconWidget
className={style.svgIcon}
icon={datasetIcon}
onClick={this.props.onScaleRangeToCurrent}
/>
</div>
<input
className={style.maxRangeInput}
type="number"
step="any"
min={this.props.dataRangeMin}
max={this.props.dataRangeMax}
value={this.props.rangeMax}
onChange={this.rangeMaxChanged}
/>
</div>
<div
className={
this.state.showOpacityControls
? style.pieceWiseEditor
: style.hidden
}
>
<PieceWiseFunctionEditorWidget
points={this.props.currentOpacityPoints}
rangeMin={this.state.showOpacityControls ? this.props.rangeMin : 1}
rangeMax={this.state.showOpacityControls ? this.props.rangeMax : 0}
onChange={this.onOpacityTransferFunctionChanged}
height={this.props.pieceWiseHeight}
width={this.props.pieceWiseWidth}
/>
</div>
<div className={style.presetList}>
<PresetListWidget
presets={presets}
height="1em"
visible={this.state.showPresetSelection}
activeName={name}
onChange={this.presetChanged}
/>
</div>
</div>
);
}
}

ColorMapEditorWidget.propTypes = {
currentOpacityPoints: PropTypes.array,
currentPreset: PropTypes.string,
dataRangeMin: PropTypes.number,
dataRangeMax: PropTypes.number,
presets: PropTypes.object,
rangeMin: PropTypes.number,
rangeMax: PropTypes.number,
onOpacityTransferFunctionChanged: PropTypes.func,
onPresetChanged: PropTypes.func,
onRangeEdited: PropTypes.func,
onScaleRangeToCurrent: PropTypes.func,
onScaleRangeOverTime: PropTypes.func,
pieceWiseHeight: PropTypes.number,
pieceWiseWidth: PropTypes.number,
};

ColorMapEditorWidget.defaultProps = {
pieceWiseHeight: 200,
pieceWiseWidth: -1,

currentOpacityPoints: undefined,
currentPreset: undefined,
dataRangeMin: undefined,
dataRangeMax: undefined,
presets: undefined,
rangeMin: undefined,
rangeMax: undefined,
onOpacityTransferFunctionChanged: undefined,
onPresetChanged: undefined,
onRangeEdited: undefined,
onScaleRangeToCurrent: undefined,
onScaleRangeOverTime: undefined,
};