kekule
Version:
Open source JavaScript toolkit for chemoinformatics
1,435 lines (1,368 loc) • 104 kB
JavaScript
/**
* @fileoverview
* Related types and classes of spectrum sub view for ChemObjDisplayer.
* @author Partridge Jiang
*/
/*
* requires /lan/classes.js
* requires /utils/kekule.utils.js
* requires /xbrowsers/kekule.x.js
* requires /core/kekule.common.js
* requries /spectroscopy/kekule.spectrum.core.js
* requires /widgets/kekule.widget.base.js
* requires /widgets/kekule.widget.menus.js
* requires /widgets/kekule.widget.dialogs.js
* requires /widgets/kekule.widget.helpers.js
* requires /widgets/kekule.widget.keys.js
* requires /widgets/chem/kekule.chemWidget.base.js
* requires /widgets/chem/kekule.chemWidget.chemObjDisplayers.js
* requires /widgets/chem/kekule.chemWidget.viewers.js
* requires /widgets/operation/kekule.actions.js
*
* requires /localization/kekule.localize.widget.js
*/
(function(){
"use strict";
Kekule._registerAfterLoadSysProc(function(){
// the following code will be run after both spectroscopy and widget modules are loaded
if (!Kekule.ChemWidget || !Kekule.Spectroscopy)
return;
var AU = Kekule.ArrayUtils;
var OU = Kekule.ObjUtils;
var ZU = Kekule.ZoomUtils;
Kekule.globalOptions.add('chemWidget.viewer', {
enableSpectrumView: true,
enableLocalSpectrumView: !false
});
/**
* Config class of spectrum sub view ({@link Kekule.ChemWidget.Viewer.SpectrumSubView}).
* @class
* @augments Kekule.AbstractConfigs
*
* @property {Bool} enableSpectrumView Whether turning on the spectrum view mode when a single spectrum object is loaded in viewer.
* @property {Bool} enableLocalSpectrumView Whether applying specified interactions to a spectrum inside chem space (with other types of objects) in viewer.
* @property {Number} spectrumAxisLabelFontSizeMin The minimal font size to draw spectrum axis labels in spectrum mode.
* @property {Number} spectrumAxisLabelFontSizeMax The maximal font size to draw spectrum axis labels in spectrum mode.
* @property {Number} spectrumAxisLabelFontSizeFixed If this value is set, the spectrum axis labels will always be drawn in this size in spectrum mode, regardless of the zoom settings.
* @property {Hash} enableSpectrumDataHotTrackOnMode Whether spectrum data hot track is enabled in certain mode.
* This property is a hash object while the key is the value of data mode.
* A 'default' key/value can be used here to provide the default setting of this property.
* @property {Hash} enableSpectrumDataSelectOnMode Whether spectrum data select is enabled in certain mode.
* This property is a hash object while the key is the value of data mode.
* A 'default' key/value can be used here to provide the default setting of this property.
* @property {Hash} enableSpectrumDataMultiSelectOnMode Whether spectrum data multi-select is enabled in certain mode.
* This property is a hash object while the key is the value of data mode.
* A 'default' key/value can be used here to provide the default setting of this property.
* @property {Hash} spectrumDataHotTrackUiMarkersOnMode Whether spectrum data multi-select is enabled in certain mode.
* This property is a hash object while the key is the value of data mode.
* A 'default' key/value can be used here to provide the default setting of this property.
* @property {Hash} spectrumDataHotTrackUiMarkersOnMode The displayed UI markers when hot tracking spectrum data.
* This property is a hash object while the key is the value of data mode.
* The hash value is an array of {@link Kekule.ChemWidget.Viewer.SpectrumSubView.UiMarker}.
* A 'default' key/value can be used here to provide the default setting of this property.
* @property {Hash} spectrumDataSelectUiMarkersOnMode The displayed UI markers when selecting spectrum data.
* This property is a hash object while the key is the value of data mode.
* The hash value is an array of {@link Kekule.ChemWidget.Viewer.SpectrumSubView.UiMarker}.
* A 'default' key/value can be used here to provide the default setting of this property.
* @property {Hash} spectrumHotTrackDataPointMarkerDrawStyles Render styles of hot track data point marker in spectrum.
* @property {Hash} spectrumSelectDataPointMarkerDrawStyles Render styles of data point selection marker in spectrum.
* @property {Hash} spectrumHotTrackedDataPointDetailMarkerDrawStyles Render styles of hot track data detail marker in spectrum.
* @property {Hash} spectrumSelectedDataPointDetailMarkerDrawStyles Render styles of data detail selection marker in spectrum.
* @property {Int} spectrumDataPointMarkerSize Size of data point UI marker.
* @property {Int} spectrumDataPointDetailMarkerPadding Padding of data point detail marker to data point marker.
* @property {Hash} spectrumPeakHotTrackStyles Render styles of hot tracked spectrum peak.
* @property {Hash} spectrumPeakSelectStyles Render styles of selected spectrum peak.
*
* @property {Number} spectrumDataPointSelectInflation
*
* @property {Array} spectrumZoomPrimaryModifierKeys Modifier keys (Shift/Ctrl/Alt) used when zooming on the primary axis of spectrum with mouse wheel.
* @property {Array} spectrumZoomSecondaryModifierKeys Modifier keys (Shift/Ctrl/Alt) used when zooming on the secondary axis of spectrum with mouse wheel.
* @property {Array} spectrumZoomBothModifierKeys Modifier keys (Shift/Ctrl/Alt) used when zooming on both axises of spectrum with mouse wheel.
*/
Kekule.ChemWidget.ChemObjDisplayerSpectrumViewConfigs = Class.create(Kekule.AbstractConfigs,
/** @lends Kekule.ChemWidget.ChemObjDisplayerSpectrumViewConfigs# */
{
/** @private */
CLASS_NAME: 'Kekule.ChemWidget.ChemObjDisplayerSpectrumViewConfigs',
/** @private */
initProperties: function()
{
this.addBoolConfigProp('enableSpectrumView', undefined);
this.addBoolConfigProp('enableLocalSpectrumView', undefined);
this.addNumConfigProp('spectrumAxisLabelFontSizeMin', 15);
this.addNumConfigProp('spectrumAxisLabelFontSizeMax', 35);
this.addNumConfigProp('spectrumAxisLabelFontSizeFixed', 18);
this.addNumConfigProp('spectrumAxisScaleLabelFontSizeMin', 13);
this.addNumConfigProp('spectrumAxisScaleLabelFontSizeMax', 32);
this.addNumConfigProp('spectrumAxisScaleLabelFontSizeFixed', 15);
// configs about spectrum data UI marker
this.addHashConfigProp('enableSpectrumDataHotTrackOnMode', undefined);
this.addHashConfigProp('enableSpectrumDataSelectOnMode', undefined);
this.addHashConfigProp('enableSpectrumDataMultiSelectOnMode', undefined);
this.addHashConfigProp('spectrumDataHotTrackUiMarkersOnMode', undefined);
this.addHashConfigProp('spectrumDataSelectUiMarkersOnMode', undefined);
//this.addBoolConfigProp('enableSpectrumDataPointMarker', true);
//this.addBoolConfigProp('enableSpectrumDataPointDetailMarker', true);
this.addHashConfigProp('spectrumHotTrackDataPointMarkerDrawStyles', undefined);
this.addHashConfigProp('spectrumSelectDataPointMarkerDrawStyles', undefined);
this.addHashConfigProp('spectrumHotTrackedDataPointDetailMarkerDrawStyles', undefined);
this.addHashConfigProp('spectrumSelectedDataPointDetailMarkerDrawStyles', undefined);
this.addIntConfigProp('spectrumDataPointMarkerSize', 15);
this.addIntConfigProp('spectrumDataPointMarkerWidth', 2);
this.addIntConfigProp('spectrumDataPointDetailMarkerValuePrecision', 8);
this.addIntConfigProp('spectrumDataPointDetailMarkerPadding', 5);
//this.addBoolConfigProp('enableSpectrumPeakHotTrack', true);
//this.addBoolConfigProp('enableSpectrumPeakSelect', true);
this.addHashConfigProp('spectrumPeakHotTrackStyles', undefined);
this.addHashConfigProp('spectrumPeakSelectStyles', undefined);
//this.addBoolConfigProp('hideSpectrumDataPointMarkerOnHotTrackedPeak', true);
this.addNumConfigProp('spectrumDataPointSelectInflation', 1.5);
//this.addBoolConfigProp('enableSpectrumDataHint', true);
this.defineProp('spectrumZoomPrimaryModifierKeys', {'dataType': DataType.ARRAY});
this.defineProp('spectrumZoomSecondaryModifierKeys', {'dataType': DataType.ARRAY});
this.defineProp('spectrumZoomBothModifierKeys', {'dataType': DataType.ARRAY});
},
/** @ignore */
initPropDefValues: function()
{
this.tryApplySuper('initPropDefValues');
var DM = Kekule.Spectroscopy.DataMode;
var value = {'default': true};
//value[DM.CONTINUOUS] = true;
//value[DM.PEAK] = true;
this.setEnableSpectrumDataHotTrackOnMode(value);
var value = {'default': false};
//value[DM.CONTINUOUS] = false;
//value[DM.PEAK] = true;
this.setEnableSpectrumDataSelectOnMode(value);
var value = {'default': false};
this.setEnableSpectrumDataMultiSelectOnMode(value);
var value = {};
value[DM.CONTINUOUS] = [SVM.DATA_POINT, SVM.DATA_DETAIL];
value[DM.PEAK] = [SVM.PEAK, SVM.DATA_DETAIL];
this.setSpectrumDataHotTrackUiMarkersOnMode(value);
var value = {};
value[DM.CONTINUOUS] = [SVM.DATA_POINT/*, SVM.DATA_DETAIL*/];
value[DM.PEAK] = [SVM.PEAK/*, SVM.DATA_DETAIL*/];
this.setSpectrumDataSelectUiMarkersOnMode(value);
this.setSpectrumHotTrackDataPointMarkerDrawStyles({
'color': '#c21717',
'strokeWidth': 1,
'opacity': 1
});
this.setSpectrumSelectDataPointMarkerDrawStyles({
'color': '#0077d6',
'strokeWidth': 1,
'opacity': 1
});
this.setSpectrumHotTrackedDataPointDetailMarkerDrawStyles({
'fontFamily': 'Arial, Helvetica, sans-serif',
'fontSize': 15,
'color': '#c21717',
'strokeWidth': 2,
'opacity': 1
});
this.setSpectrumSelectedDataPointDetailMarkerDrawStyles({
'fontFamily': 'Arial, Helvetica, sans-serif',
'fontSize': 15,
'color': '#0077d6',
'strokeWidth': 2,
'opacity': 1
});
this.setSpectrumPeakHotTrackStyles({
'color': '#c21717'
});
this.setSpectrumPeakSelectStyles({
//'color': '#f50f0f'
'color': '#0077d6',
'spectrum_dataStrokeWidthRatio': 0.05
});
this.setSpectrumZoomPrimaryModifierKeys([]);
this.setSpectrumZoomSecondaryModifierKeys(['shift']);
this.setSpectrumZoomBothModifierKeys(['alt']);
},
/** @ignore */
initPropValues: function()
{
this.tryApplySuper('initPropValues');
//this.setEnableSpectrumView(Kekule.globalOptions.chemWidget.viewer.enableSpectrumView);
//this.setEnableLocalSpectrumView(Kekule.globalOptions.chemWidget.viewer.isLocalSpectrumViewEnabled);
},
getActualEnableSpectrumView: function()
{
return Kekule.oneOf(this.getEnableSpectrumView(), Kekule.globalOptions.chemWidget.viewer.enableSpectrumView);
},
getActualEnableLocalSpectrumView: function()
{
return Kekule.oneOf(this.getEnableLocalSpectrumView(), Kekule.globalOptions.chemWidget.viewer.enableLocalSpectrumView);
},
getDataModeSpecifiedConfigValue: function(propName, dataMode)
{
var configValue = this.getPropValue(propName);
if (DataType.isObjectValue(configValue))
{
var result = configValue[dataMode];
if (result === undefined)
result = configValue.default;
return result;
}
else
return configValue;
},
setDataModeSpecifiedConfigValue: function(propName, value, dataMode)
{
var configValue = this.getPropValue(propName);
if (!configValue)
{
configValue = {};
this.setPropValue(propName, configValue);
}
if (Kekule.ObjUtils.notUnset(dataMode))
configValue[dataMode] = value;
else
configValue.default = value;
},
/** @private */
getDataModeSpecifiedBoolConfigValueOfModeList: function(propName, dataModes, opAnd)
{
var modes = AU.toArray(dataModes);
var result = this.getDataModeSpecifiedConfigValue(propName, modes[0]);
if (!result && opAnd)
return result;
for (var i = 0, l = modes.length; i < l; ++i)
{
if (opAnd)
{
result = result && this.getDataModeSpecifiedConfigValue(propName, modes[i]);
if (!result)
return result;
}
else
result = result || this.getDataModeSpecifiedConfigValue(propName, modes[i]);
}
return result;
}
});
// Extend ChemObjDisplayerConfigs, add ChemObjDisplayerSpectrumViewConfigs into it
ClassEx.extendMethods(Kekule.ChemWidget.ChemObjDisplayerConfigs, {
'initProperties': function($origin)
{
$origin();
this.addConfigProp('spectrumViewConfigs', 'Kekule.ChemWidget.ChemObjDisplayerSpectrumViewConfigs');
},
'initPropDefValues': function($origin)
{
$origin();
this.setPropStoreFieldValue('spectrumViewConfigs', new Kekule.ChemWidget.ChemObjDisplayerSpectrumViewConfigs());
}
});
/**
* A facade sub view class to wrap all methods about spectrum for {@link Kekule.ChemWidget.Viewer}.
* @class
* @augments Kekule.ChemWidget.ViewerSubView
*
* @property {Kekule.ChemWidget.Viewer} viewer Parent viewer object. Readonly.
* @property {Kekule.Spectroscopy.Spectrum} spectrum Target spectrum of sub view.
* @property {Hash} viewportRanges The viewport range of spectrum in this sub view.
* @property {Array} hotTrackedDataItemsEx Array of hot track data items. Each item is a hash {dataSection, dataValue}.
* @property {Array} selectedDataItemEx Array of selected data items. Each item is a hash {dataSection, dataValue}.
*/
/**
* Invoked when the pointer is hot tracking on a spectrum data item.
* event param of it has fields: {spectrum: {@link Kekule.Spectroscopy.Spectrum}, dataItems: array of {dataSection, dataValue}}.
* @name Kekule.ChemWidget.Viewer.SpectrumSubView#hotTrackOnSpectrumData
* @event
*/
/**
* Invoked when the spectrum data item(s) is selected in view.
* event param of it has fields: {spectrum: {@link Kekule.Spectroscopy.Spectrum}, dataItems: array of {dataSection, dataValue}}.
* @name Kekule.ChemWidget.Viewer.SpectrumSubView#spectrumDataSelectionChange
* @event
*/
Kekule.ChemWidget.Viewer.SpectrumSubView = Class.create(Kekule.ChemWidget.ViewerSubView,
/** @lends Kekule.ChemWidget.Viewer.SpectrumSubView# */
{
/** @private */
CLASS_NAME: 'Kekule.ChemWidget.Viewer.SpectrumSubView',
/** @constructs */
initialize: function(parent, targetObj)
{
this.tryApplySuper('initialize', [parent, targetObj]);
},
/** @private */
initProperties: function()
{
// the target spectrum object
this.defineProp('spectrum', {
'dataType': 'Kekule.Spectroscopy.Spectrum',
'serializable': false,
'getter': function() { return this.getTarget(); },
'setter': function(value) { this.setTarget(value); }
});
// the viewport range of spectrum view
this.defineProp('viewportRanges', {
'dataType': DataType.HASH,
'serializable': false
/*
'getter': function()
{
var cache = this._getSpectrumRenderCache();
return cache && cache.viewportRanges;
},
'setter': function(value)
{
var cache = this._getSpectrumRenderCache();
if (cache)
cache.viewportRanges = value;
}
*/
//'getter': function() { return this.getViewer().getSpectrumViewportRanges(); },
//'setter': function(value) { this.getViewer().setSpectrumViewportRanges(value); }
});
// private, the hot tracked and selected spectrum peak
this.defineProp('hotTrackedDataItem', {
'dataType': DataType.OBJECT,
'serializable': false,
'getter': function()
{
var itemEx = this.getHotTrackedDataItemEx();
return itemEx && itemEx.dataItem;
},
'setter': function(value)
{
var section = value && this._findSectionOfDataItem(value, true);
var itemEx = section? {'section': section, 'dataValue': value}: null;
this.changeHotTrackedDataItem(itemEx, true);
}
});
this.defineProp('hotTrackedDataItemEx', {
'dataType': DataType.OBJECT,
'serializable': false,
'getter': function()
{
var itemsEx = this.getHotTrackedDataItemsEx();
return itemsEx && itemsEx[0];
},
'setter': function(value)
{
var itemsEx = this._fetchDataItemsEx(value);
this.changeHotTrackedDataItems(itemsEx, true);
}
});
this.defineProp('hotTrackedDataItemsEx', {
'dataType': DataType.ARRAY,
'serializable': false,
'getter': function()
{
return this.getPropStoreFieldValue('hotTrackedDataItemsEx') || [];
},
'setter': function(value)
{
this.changeHotTrackedDataItems(value, true);
}
});
this.defineProp('selectedDataItem', {
'dataType': DataType.OBJECT,
'serializable': false,
'getter': function(value)
{
var itemEx = this.getSelectedDataItemEx();
return itemEx && itemEx.dataItem;
},
'setter': function(value)
{
var section = value && this._findSectionOfDataItem(value, true);
var itemEx = section? {'section': section, 'dataValue': value}: null;
this.changeSelectedDataItems(itemEx && [itemEx], true);
}
});
this.defineProp('selectedDataItems', {
'dataType': DataType.ARRAY,
'serializable': false,
'getter': function(value)
{
var itemsEx = this.getSelectedDataItemsEx();
if (itemsEx)
{
var result = [];
for (var i = 0, l = itemsEx.length; i < l; ++i)
{
result.push(itemsEx[i].dataItem);
}
return result;
}
else
return [];
},
'setter': function(value)
{
var itemsEx = this._fetchDataItemsEx(value);
this.changeSelectedDataItems(itemsEx, true);
}
});
this.defineProp('selectedDataItemEx', {
'dataType': DataType.OBJECT,
'serializable': false,
'getter': function()
{
var itemsEx = this.getSelectedDataItemsEx();
return itemsEx && itemsEx[0];
},
'setter': function(value)
{
this.changeSelectedDataItems(value && [value], true);
}
});
this.defineProp('selectedDataItemsEx', {
'dataType': DataType.ARRAY,
'serializable': false,
'getter': function()
{
return this.getPropStoreFieldValue('selectedDataItemsEx') || [];
},
'setter': function(value)
{
this.changeSelectedDataItems(value, true);
}
});
// whether the spectrum is displayed with reversed axises position in spectrum view
this.defineProp('isSpectrumWithReversedAxises', {
'dataType': DataType.BOOL,
'serializable': false,
'setter': null,
'getter': function()
{
var renderCache = this._getSpectrumRenderCache();
return !!(renderCache && renderCache.spectrum_reversedAxises);
}
});
},
/** @ignore */
appliableToTarget: function(obj)
{
return obj instanceof Kekule.Spectroscopy.Spectrum;
},
/** @private */
_getSpectrumRenderer: function()
{
var spectrum = this.getSpectrum();
if (spectrum)
{
var context = this.getViewer().getDrawContext();
var rootRenderer = this.getViewer().getRootRenderer();
var renderer = rootRenderer && rootRenderer.getDirectRendererForChildObj && rootRenderer.getDirectRendererForChildObj(context, spectrum);
return renderer;
}
else
return null;
},
/** @private */
_getSpectrumRenderCache: function()
{
var renderer = this._getSpectrumRenderer();
var context = this.getViewer().getDrawContext();
return renderer && renderer.getRenderCache(context);
},
/**
* Returns all the data modes of displayed data section of spectrum.
* @returns {Array}
*/
getDisplayedDataModes: function()
{
var spectrum = this.getSpectrum();
var sections = (spectrum && spectrum.getDisplayedDataSections() || []);
var result = [];
for (var i = 0, l = sections.length; i < l; ++i)
{
result.push(sections[i].getMode());
}
return result;
},
/**
* Returns the client screen box of spectrum data curve (without the axis and labels).
* @returns {Hash}
*/
getClientScreenBox: function()
{
var viewer = this.getViewer();
//if (viewer.isInSpectrumMode())
{
var spectrum = this.getSpectrum(); //viewer.getChemObj();
if (spectrum)
{
var boundInfoRecorder = viewer.getBoundInfoRecorder();
var bound = boundInfoRecorder && boundInfoRecorder.getBound(viewer.getDrawContext(), spectrum.getPseudoRenderSubObject('data'));
if (bound.shapeType === Kekule.Render.MetaShapeType.RECT)
{
return Kekule.BoxUtils.createBox(bound.coords[0], bound.coords[1]);
}
else
return null;
}
}
return null;
},
/** @private */
fetchViewportRanges: function()
{
var result = {};
var VD = Kekule.VarDependency;
result[VD.INDEPENDENT] = this.getViewportRange(VD.INDEPENDENT);
result[VD.DEPENDENT] = this.getViewportRange(VD.DEPENDENT);
return result;
},
/**
* Returns the actual spectrum view port range of a var axis.
* @param {Int} varDependency
* @returns {Hash}
*/
getViewportRange: function(varDependency)
{
var result = (this.getViewportRanges() || {})[varDependency] || {};
return Object.extend({'rangeFrom': 0, 'rangeTo': 1}, result);
},
/**
* Set the spectrum viewport range of a var axis.
* @param {Int} varDependency
* @param {Number} rangeFrom
* @param {Number} rangeTo
*/
setViewportRange: function(varDependency, rangeFrom, rangeTo)
{
var ranges = this.getViewportRanges();
if (!ranges)
{
ranges = {};
this.setViewportRanges(ranges);
}
var range = ranges[varDependency];
if (!range)
{
range = {};
ranges[varDependency] = range;
}
range.rangeFrom = Kekule.oneOf(rangeFrom, 0);
range.rangeTo = Kekule.oneOf(rangeTo, 1);
this.applyToRenderOptions();
return this;
},
/**
* Reset the spectrum viewport range.
* @param {Int} varDependency If not set, both dep/indep vars will be reset.
*/
resetViewportRange: function(varDependency)
{
if (Kekule.ObjUtils.isUnset(varDependency))
this.setViewportRanges(undefined);
else
{
var old = this.getViewportRange(varDependency);
if (old && old[varDependency])
delete old[varDependency];
}
this.applyToRenderOptions();
},
/** @private */
getViewportZoomInfo: function(varDependency)
{
if (!varDependency)
varDependency = Kekule.VarDependency.INDEPENDENT;
var range = this.getViewportRange(varDependency);
return {
'zoom': 1 / Math.abs(range.rangeTo - range.rangeFrom),
'center': (range.rangeTo + range.rangeFrom) / 2
};
},
/** @private */
setViewportZoom: function(varDependency, zoom, zoomCenter)
{
if (!varDependency)
varDependency = Kekule.VarDependency.INDEPENDENT;
if (Kekule.ObjUtils.isUnset(zoomCenter))
{
var oldZoomInfo = this.getViewportZoomInfo(varDependency);
zoomCenter = oldZoomInfo.center;
}
var delta = 1 / zoom / 2;
var range = {
'rangeFrom': zoomCenter - delta,
'rangeTo': zoomCenter + delta
};
this.setViewportRange(varDependency, range.rangeFrom, range.rangeTo);
},
/** @private */
_zoomViewportTo: function(value, zoomCenterCoord, direction, varDependency)
{
var clientBox = this.getClientScreenBox();
var currViewportRange = this.getViewportRange(varDependency);
var oldRangeValue = currViewportRange.rangeTo - currViewportRange.rangeFrom;
var newRangeValue = 1 / value;
var rangeDelta = newRangeValue - oldRangeValue;
var fixedPointRatio;
if (!zoomCenterCoord)
fixedPointRatio = 0.5;
else
{
fixedPointRatio = (direction === 'x')?
((zoomCenterCoord.x - clientBox.x1) / (clientBox.x2 - clientBox.x1)):
((clientBox.y2 - zoomCenterCoord.y) / (clientBox.y2 - clientBox.y1));
}
var newRangeFrom = currViewportRange.rangeFrom - rangeDelta * fixedPointRatio;
var newRangeTo = currViewportRange.rangeTo + rangeDelta * (1 - fixedPointRatio);
this.setViewportRange(varDependency, newRangeFrom, newRangeTo);
return this;
},
/**
* Zoom the spectrum viewport.
* @param {Number} delta
* @param {Hash} zoomCenterCoord
* @param {Array} directions e.g. ['x', 'y'].
* @private
*/
zoomViewportByDelta: function(delta, zoomCenterCoord, directions)
{
var viewer = this.getViewer();
//if (viewer.isInSpectrumMode())
//if (viewer.enableSpectrumInteraction())
{
viewer.beginUpdate();
try
{
for (var i = 0, l = directions.length; i < l; ++i)
{
var direction = directions[i];
var targetOnIndep = direction === 'x';
var reversedAxises = this.getIsSpectrumWithReversedAxises();
if (reversedAxises)
targetOnIndep = !targetOnIndep;
var varDependency = targetOnIndep ? Kekule.VarDependency.INDEPENDENT : Kekule.VarDependency.DEPENDENT;
var zoomRatio;
var curr = this.getViewportZoomInfo(varDependency).zoom;
if (delta > 0)
{
zoomRatio = ZU.getNextZoomInRatio(curr, delta);
}
else if (delta < 0)
{
zoomRatio = ZU.getNextZoomOutRatio(curr, -delta);
}
this._zoomViewportTo(zoomRatio, zoomCenterCoord, direction, varDependency);
}
}
finally
{
viewer.endUpdate(); // repaint here
}
//viewer.geometryOptionChanged();
}
},
/** @private */
_applyViewportRanges: function(/*affectedOptions*/)
{
var viewer = this.getViewer();
//if (viewer.isInSpectrumMode())
{
var varDependencies = [Kekule.VarDependency.INDEPENDENT, Kekule.VarDependency.DEPENDENT];
var varTypes = ['independent', 'dependent'];
var targetSpectrum = this.getTarget();
for (var i = 0, ii = varTypes.length; i < ii; ++i)
{
var viewPortRange = this.getViewportRange(varDependencies[i]);
var optionNameFrom = 'spectrum_viewport' + varTypes[i].upperFirst() + 'DataRangeFrom';
var optionNameTo = 'spectrum_viewport' + varTypes[i].upperFirst() + 'DataRangeTo';
/*
affectedOptions[optionNameFrom] = viewPortRange.rangeFrom;
affectedOptions[optionNameTo] = viewPortRange.rangeTo;
*/
var overrideOptions = {};
overrideOptions[optionNameFrom] = viewPortRange.rangeFrom;
overrideOptions[optionNameTo] = viewPortRange.rangeTo;
targetSpectrum.addOverrideRenderOptionItem(overrideOptions);
}
}
},
/**
* Apply spectrum view settings to render options of viewer.
* @param {Object} renderOptions
* @private
*/
applyToRenderOptions: function(/*renderOptions*/)
{
this._applyViewportRanges(/*renderOptions*/);
this.doRepaintSpectrum();
},
/** @private */
doRepaintSpectrum: function()
{
var viewer = this.getViewer();
var renderer = viewer.getRootRenderer();
if (renderer)
{
//console.log('request update');
renderer.update(viewer.getDrawContext(), [{'obj': this.getTarget()}]);
this.updateSpectrumDataItemUiMarkers(); // update the UI marker position since the data rendering has been changed
//this.getViewer().repaintUiMarker();
}
},
/** @private */
_getHotTrackedDataItemRenderStyles: function()
{
var viewer = this.getViewer();
return viewer && viewer.getDisplayerConfigs().getSpectrumViewConfigs().getSpectrumPeakHotTrackStyles();
},
/** @private */
_getSelectedDataItemRenderStyles: function()
{
var viewer = this.getViewer();
return viewer && viewer.getDisplayerConfigs().getSpectrumViewConfigs().getSpectrumPeakSelectStyles();
},
/** @private */
_findSectionOfDataItem: function(dataItem, displayedSectionOnly)
{
var spectrum = this.getSpectrum();
var sections = displayedSectionOnly? spectrum.getDisplayedDataSections(): spectrum.getDataSections();
for (var i = 0, l = sections.length; i < l; ++i)
{
var section = sections[i];
if (section.indexOfDataItem(dataItem) >= 0)
return section;
}
return null;
},
/** @private */
_fetchDataItemsEx: function(value)
{
var items = value? AU.toArray(value): [];
var itemsEx = [];
for (var i = 0, l = items.length; i < l; ++i)
{
var item = items[i];
var itemEx;
if (DataType.isObjectValue(item) && item.section && item.dataValue) // is already Ex hash
itemEx = item;
else
{
var section = item && this._findSectionOfDataItem(item, true);
itemEx = section ? {'section': section, 'dataValue': item} : null;
}
if (itemEx)
itemsEx.push(itemEx);
}
return itemsEx;
},
/** @private */
_indexOfDataItemEx: function(itemEx, itemExList)
{
var result = itemExList.indexOf(itemEx);
if (result <= 0)
{
for (var i = 0, l = itemExList.length; i < l; ++i)
{
var curr = itemExList[i];
if (itemEx.section && curr.section === itemEx.section)
{
if (itemEx.section.isPeakSection())
{
var currDataSrc = curr.section._getDataValueSrc(curr.dataValue);
if (currDataSrc && itemEx.section._getDataValueSrc(itemEx.dataValue) === currDataSrc)
{
result = i;
break;
}
}
else
{
if (OU.equal(itemEx.dataValue, curr.dataValue))
{
result = i;
break;
}
}
}
}
}
return result;
},
/**
* Add data item(s) to selection.
* @param {Variant} items
*/
addToSelection: function(items)
{
var selection = AU.clone(this.getSelectedDataItemsEx());
var itemsEx = this._fetchDataItemsEx(items);
for (var i = 0, l = itemsEx.length; i < l; ++i)
{
var itemEx = itemsEx[i];
if (this._indexOfDataItemEx(itemEx, selection) >= 0) // already inside, bypass
continue;
else
selection.push(itemEx);
}
this.changeSelectedDataItems(selection, true);
},
/**
* Remove data item(s) from selection.
* @param {Variant} items
*/
removeFromSelection: function(items)
{
var selection = AU.clone(this.getSelectedDataItemsEx());
var itemsEx = this._fetchDataItemsEx(items);
for (var i = 0, l = itemsEx.length; i < l; ++i)
{
var itemEx = itemsEx[i];
var index = this._indexOfDataItemEx(itemEx, selection);
if (index >= 0) // inside, remove it
{
selection.splice(index, 1);
}
}
this.changeSelectedDataItems(selection, true);
},
/**
* Toggle selection state of data items.
* @param {Variant} items
*/
toggleSelectingState: function(items)
{
var selection = AU.clone(this.getSelectedDataItemsEx());
var itemsEx = this._fetchDataItemsEx(items);
for (var i = 0, l = itemsEx.length; i < l; ++i)
{
var itemEx = itemsEx[i];
var index = this._indexOfDataItemEx(itemEx, selection);
if (index >= 0) // inside, remove it
{
selection.splice(index, 1);
}
else // not inside, add it
{
selection.push(itemEx);
}
}
this.changeSelectedDataItems(selection, true);
},
/**
* Select data item(s).
* @param {Variant} items
*/
select: function(items)
{
var itemsEx = this._fetchDataItemsEx(items);
this.changeSelectedDataItems(itemsEx, true);
},
/** @private */
doClearHotTrackedItems: function()
{
this.changeHotTrackedDataItems(null, false);
},
/** @private */
doClearSelectedItems: function()
{
this.changeSelectedDataItems(null, false);
},
/**
* Called when the hot tracked peak item is changed.
* @private
*/
_hotTrackedDataItemsChanged: function(oldItemsEx, newItemsEx)
{
this._hotTrackedOrSelectDataItemsChanged(oldItemsEx, newItemsEx, false);
this.invokeEvent('hotTrackOnSpectrumData', {
'spectrum': this.getSpectrum(),
'dataItems': newItemsEx,
'prevDataItems': oldItemsEx
});
},
/**
* Called when the selected peak item is changed.
* @private
*/
_selectedDataItemsChanged: function(oldItemsEx, newItemsEx)
{
this._hotTrackedOrSelectDataItemsChanged(oldItemsEx, newItemsEx, true);
this.invokeEvent('spectrumDataSelectionChange', {
'spectrum': this.getSpectrum(),
'dataItems': newItemsEx,
'prevDataItems': oldItemsEx
});
/*
var spectrum = this.getSpectrum();
if (oldItemEx)
{
if (this._selectedDataItemRenderStyles)
spectrum.removeDataItemOverrideRenderOptionItem(oldItemEx.dataValue, this._selectedDataItemRenderStyles);
}
if (newItemEx)
{
var renderStyles = this._getSelectedDataItemRenderStyles();
if (renderStyles)
{
spectrum.addDataItemOverrideRenderOptionItem(newItemEx.dataValue, renderStyles);
this._selectedDataItemRenderStyles = renderStyles;
}
}
*/
},
/** @private */
_hotTrackedOrSelectDataItemsChanged: function(oldItemsEx, newItemsEx, isSelect)
{
var viewer = this.getViewer();
var spectrum = this.getSpectrum();
var needRepaintSpectrum = false;
//var configs = this.getViewer().getDisplayerConfigs().getSpectrumViewConfigs();
var dataItemRenderStylesField = isSelect? '_selectDataItemRenderStyles': '_hotTrackedDataItemRenderStyles';
if (newItemsEx && newItemsEx.length) // empty hot tracked or select item in other sub views
{
/*
this._removeHotTrackedOrSelectedDataItemInSiblingSpectrumViews(isSelect);
if (isSelect)
viewer.setVisibleOfUiMarkerGroup(Kekule.ChemWidget.ViewerUiMarkerGroup.SELECT, false, false);
else
viewer.setVisibleOfUiMarkerGroup(Kekule.ChemWidget.ViewerUiMarkerGroup.HOTTRACK, false, false);
*/
if (isSelect)
viewer.clearSelectedItems([this], false);
else
viewer.clearHotTrackedItems([this], false);
}
if (oldItemsEx)
{
for (var i = 0, l = oldItemsEx.length; i < l; ++i)
{
this._updateHotTrackOrSelectUiMarkerToDataItem(null, isSelect, i); // hide old markers
if (this[dataItemRenderStylesField])
{
spectrum.removeDataItemOverrideRenderOptionItem(oldItemsEx[i].dataValue, this[dataItemRenderStylesField]);
needRepaintSpectrum = true;
}
}
}
if (newItemsEx)
{
for (var i = 0, l = newItemsEx.length; i < l; ++i)
{
var updateDataItemResult = this._updateHotTrackOrSelectUiMarkerToDataItem(newItemsEx[i], isSelect, i);
if (updateDataItemResult.needRepaintSpectrum)
needRepaintSpectrum = true;
}
}
else
this._updateHotTrackOrSelectUiMarkerToDataItem(null, isSelect);
//viewer.updateUiMarkers(true);
if (needRepaintSpectrum)
viewer.requestRepaint();
},
/* @private */
/*
_removeHotTrackedOrSelectedDataItemInSiblingSpectrumViews(isSelect)
{
var viewer = this.getViewer();
var self = this;
viewer.iterateSubViews(function(subView){
if (subView !== self && subView instanceof Kekule.ChemWidget.Viewer.SpectrumSubView)
{
if (isSelect)
subView.changeSelectedDataItems(null, false);
else
subView.changeHotTrackedDataItems(null, false);
}
});
},
*/
/** @private */
_updateHotTrackOrSelectUiMarkerToDataItem: function(dataItemEx, isSelect, markerIndex)
{
var viewer = this.getViewer();
var configs = this.getViewer().getDisplayerConfigs().getSpectrumViewConfigs();
var dataItemRenderStylesField = isSelect? '_selectDataItemRenderStyles': '_hotTrackedDataItemRenderStyles';
var uiMarkerElements = (dataItemEx && dataItemEx.dataValue)?
(isSelect? this._getSpectrumDataSelectElements(configs, dataItemEx.section): this._getSpectrumDataHotTrackElements(configs, dataItemEx.section)):
[];
var dataPointMarkerVisible = uiMarkerElements.indexOf(SVM.DATA_POINT) >= 0;
var dataDetailMarkerVisible = uiMarkerElements.indexOf(SVM.DATA_DETAIL) >= 0;
var detailMarkerName = isSelect? 'selectDataDetail': 'hotTrackDataDetail';
//if (isSelect && OU.notUnset(markerIndex))
detailMarkerName += (markerIndex || 0);
var pointMarkerName = isSelect? 'selectDataPoint': 'hotTrackDataPoint';
//if (isSelect && OU.notUnset(markerIndex))
pointMarkerName += (markerIndex || 0);
var detailMarker = viewer.getSpectrumUiMarker(detailMarkerName, !!dataDetailMarkerVisible);
var pointMarker = viewer.getSpectrumUiMarker(pointMarkerName, !!dataPointMarkerVisible);
//console.log('hot track', newItemEx, hotTrackElements);
var needRepaintSpectrum = false;
if (dataItemEx && uiMarkerElements.length) // do need to display some hot track elements
{
var spectrum = this.getSpectrum();
var dataValue = dataItemEx.dataValue;
var dataSection = dataItemEx.section;
//if (hotTrackElements.length) // do need to display some hot track elements
{
if (dataSection.isPeakSection() && (uiMarkerElements.indexOf(SVM.PEAK) >= 0)) // hot track peak
{
var renderStyles = isSelect? this._getSelectedDataItemRenderStyles(): this._getHotTrackedDataItemRenderStyles();
if (renderStyles)
{
spectrum.addDataItemOverrideRenderOptionItem(dataItemEx.dataValue, renderStyles);
this[dataItemRenderStylesField] = renderStyles;
needRepaintSpectrum = true;
}
}
if (dataPointMarkerVisible || dataDetailMarkerVisible)
{
var clientBox = this.getClientScreenBox();
var baseContextCoord = this.calcCoordAtSpectrumData(dataValue, Kekule.Render.CoordSystem.CONTEXT);
var detailText = null;
if (dataDetailMarkerVisible) // data detail
detailText = this._formatSpectrumDataValueString(dataValue, configs.getSpectrumDataPointDetailMarkerValuePrecision());
//console.log('update', dataValue, detailText);
//this._updateSpectrumCurrDataPointMarker(baseContextCoord, detailText, dataPointMarkerVisible, dataDetailMarkerVisible, clientBox);
}
var detailStyles = isSelect? configs.getSpectrumSelectedDataPointDetailMarkerDrawStyles(): configs.getSpectrumHotTrackedDataPointDetailMarkerDrawStyles();
var pointStyles = isSelect? configs.getSpectrumSelectDataPointMarkerDrawStyles(): configs.getSpectrumHotTrackDataPointMarkerDrawStyles();
this._updateDataDetailMarker(detailMarker, baseContextCoord, {'text': detailText}, dataDetailMarkerVisible, detailStyles, clientBox, false);
this._updateDataPointMarker(pointMarker, baseContextCoord, null, dataPointMarkerVisible, pointStyles, clientBox, false);
}
}
else
{
if (detailMarker)
viewer.hideUiMarker(detailMarker, false);
if (pointMarker)
viewer.hideUiMarker(pointMarker, false);
}
//viewer.repaintUiMarker();
return {'needRepaintSpectrum': needRepaintSpectrum};
},
/**
* Recalculate the position and content of hot track / select UI markers according to the properties of this sub view.
* Note this method will not force the repaint.
* @private
*/
updateSpectrumDataItemUiMarkers: function(updateVisibleOnly)
{
//this.getViewer()._hideAllSpectrumUiMarkers(false); // hide all first, then update
// hot tracked
var hotTrackedDataItemsEx = this.getHotTrackedDataItemsEx();
if (hotTrackedDataItemsEx)
{
for (var i = 0, l = hotTrackedDataItemsEx.length; i < l; ++i)
{
var hotTrackedDataItemEx = hotTrackedDataItemsEx[i];
this._updateHotTrackOrSelectUiMarkerToDataItem(hotTrackedDataItemEx, false, i);
}
}
else if (!updateVisibleOnly)
{
this._updateHotTrackOrSelectUiMarkerToDataItem(null, false, 0);
}
// selected
var selectedDataItemsEx = this.getSelectedDataItemsEx();
if (selectedDataItemsEx)
{
for (var i = 0, l = selectedDataItemsEx.length; i < l; ++i)
{
var selectedDataItemEx = selectedDataItemsEx[i];
this._updateHotTrackOrSelectUiMarkerToDataItem(selectedDataItemEx, true, i);
}
}
else if (!updateVisibleOnly)
{
this._updateHotTrackOrSelectUiMarkerToDataItem(null, true, 0);
}
},
/** @private */
_isSameHotTrackedOrSelectedItems: function(objs1, objs2)
{
var o1 = objs1, o2 = objs2;
if (o1 && !o1.length)
o1 = null;
if (o2 && !o2.length)
o2 = null;
if (o1 == o2)
return true;
else if (o1 && o2)
{
return AU.compare(o1, o2, function(a, b) { return (a === b)? 0: -1}) === 0;
}
else // !objs1 || !objs2
return false;
},
/** @private */
changeHotTrackedDataItems: function(newItemsEx, doRepaint)
{
var old = this.getHotTrackedDataItemsEx();
if (!this._isSameHotTrackedOrSelectedItems(old, newItemsEx))
{
var viewer = this.getViewer();
if (doRepaint)
viewer.beginUpdateUiMarkers();
try
{
this.setPropStoreFieldValue('hotTrackedDataItemsEx', newItemsEx);
this._hotTrackedDataItemsChanged(old, newItemsEx);
if (doRepaint)
viewer.updateUiMarkers(true);
}
finally
{
if (doRepaint)
viewer.endUpdateUiMarkers();
}
}
},
/** @private */
changeSelectedDataItems: function(newItemsEx, doRepaint)
{
var old = this.getSelectedDataItemsEx();
if (!this._isSameHotTrackedOrSelectedItems(old, newItemsEx))
{
var viewer = this.getViewer();
if (doRepaint)
viewer.beginUpdateUiMarkers();
try
{
this.setPropStoreFieldValue('selectedDataItemsEx', newItemsEx);
this._selectedDataItemsChanged(old, newItemsEx);
if (doRepaint)
viewer.updateUiMarkers(true);
}
finally
{
if (doRepaint)
viewer.endUpdateUiMarkers();
}
}
},
// methods about UI markers /////////
/** @private */
_getSpectrumDataHotTrackElements: function(spectrumViewConfigs, dataSection)
{
var configs = spectrumViewConfigs;
var dataMode = dataSection.getMode();
var needHotTrack = configs.getDataModeSpecifiedConfigValue('enableSpectrumDataHotTrackOnMode', dataMode);
var activeMarkers = !needHotTrack? []: configs.getDataModeSpecifiedConfigValue('spectrumDataHotTrackUiMarkersOnMode', dataMode);
return activeMarkers;
},
/** @private */
_getSpectrumDataSelectElements: function(spectrumViewConfigs, dataSection)
{
var configs = spectrumViewConfigs;
var dataMode = dataSection.getMode();
var needSelect = configs.getDataModeSpecifiedConfigValue('enableSpectrumDataSelectOnMode', dataMode);
var activeMarkers = !needSelect? []: configs.getDataModeSpecifiedConfigValue('spectrumDataSelectUiMarkersOnMode', dataMode);
return activeMarkers;
},
/** @private */
_formatSpectrumDataValueString: function(spectrumDataValue, precision)
{
var dataVarSymbols = Kekule.ObjUtils.getOwnedFieldNames(spectrumDataValue);
var detailTextParts = [];
for (var i = 0, l = dataVarSymbols.length; i < l; ++i)
{
if (Kekule.NumUtils.isNormalNumber(spectrumDataValue[dataVarSymbols[i]]))
detailTextParts.push(dataVarSymbols[i] + ': ' + spectrumDataValue[dataVarSymbols[i]].toPrecision(precision));
}
return detailTextParts.join(', ');
},
/** @private */
_updateDataPointMarker: function(marker, contextCoord, params, visible, styles, spectrumClientBox, doRepaint)
{
if (!marker)
return;
var viewer = this.getViewer();
var pVisible = visible && contextCoord;
if (pVisible)
{
var isInideBox = Kekule.CoordUtils.isInsideBox(contextCoord, spectrumClientBox);
pVisible = !!isInideBox;
}
if (!pVisible)
{
viewer.hideUiMarker(marker, doRepaint);
}
else // if (pVisible)
{
//if (pVisible)
{
var configs = viewer.getDisplayerConfigs().getSpectrumViewConfigs();
var unitLength = viewer.getRenderConfigs().getLengthConfigs().getUnitLength() || 1;
// TODO: currently the shape is fixed to a cross
var shapeInfo;
var lineWidth = (configs.getSpectrumDataPointMarkerWidth() || 1) * unitLength;
var c = contextCoord;
if (configs.getSpectrumDataPointMarkerSize())
{
var halfSize = (configs.getSpectrumDataPointMarkerSize() / 2) * unitLength;
shapeInfo = [
Kekule.Render.MetaShapeUtils.createShapeInfo(
Kekule.Render.MetaShapeType.LINE,
[{'x': c.x - halfSize, 'y': c.y}, {'x': c.x + halfSize, 'y': c.y}], {'width': lineWidth}
),
Kekule.Render.MetaShapeUtils.createShapeInfo(
Kekule.Render.MetaShapeType.LINE,
[{'x': c.x, 'y': c.y - halfSize}, {'x': c.x, 'y': c.y + halfSize}], {'width': lineWidth}
)
];
}
else if (spectrumClientBox) // a cross all over spectrum client area
{
shapeInfo = [
Kekule.Render.MetaShapeUtils.createShapeInfo(
Kekule.Render.MetaShapeType.LINE,
[{'x': spectrumClientBox.x1, 'y': c.y}, {'x': spectrumClientBox.x2, 'y': c.y}], {'width': lineWidth}
),
Kekule.Render.MetaShapeUtils.createShapeInfo(
Kekule.Render.MetaShapeType.LINE,
[{'x': c.x, 'y': spectrumClientBox.y1}, {'x': c.x, 'y': spectrumClientBox.y2}], {'width': lineWidth}
)
];
}
var pointDrawStyles = Object.create(/*configs.getSpectrumDataPointMarkerDrawStyles()*/styles);
pointDrawStyles.strokeWidth *= unitLength;
viewer.modifyShapeBasedMarker(marker, shapeInfo, pointDrawStyles, false);
viewer.showUiMarker(marker, doRepaint);
}
}
},
/** @private */
_updateDataDetailMarker: function(marker, contextCoord, params, visible, styles, spectrumClientBox, doRepaint)
{
if (!marker)
return;
var viewer = this.getViewer();
var text = params.text;
var pVisible = visible && contextCoord && text;
if (pVisible)
{
var isInideBox = Kekule.CoordUtils.isInsideBox(contextCoord, spectrumClientBox);
pVisible = !!isInideBox;
}
if (!pVisible)
{
viewer.hideUiMarker(marker, doRepaint);
}
else
{
var configs = viewer.getDisplayerConfigs().getSpectrumViewConfigs();
var unitLength = viewer.getRenderConfigs().getLengthConfigs().getUnitLength() || 1;
var detailDrawStyles = Object.create(/*configs.getSpectrumDataPointDetailMarkerDrawStyles()*/styles);
detailDrawStyles.fontSize *= unitLength;
if (text)
{
// determinate the position of detail text
var drawBridge = viewer.getDrawBridge();
var canMeasureText = drawBridge.canMeasureText && drawBridge.canMeasureText();
var canMeasureDrawnText = drawBridge.canMeasureDrawnText && drawBridge.canMeasureDrawnText();
var canModifyText = drawBridge.canMeasureText && drawBridge.canModifyText();
var textBox;
if (canMeasureText)
textBox = drawBridge.measureText(viewer.getDrawContext(), text, detailDrawStyles);
else if (canMeasureDrawnText && canModifyText)
{
// draw the text out first
//this.modifyTextBasedMarker(marker, null, text, detailDrawStyles, true);
var context = this.getViewer().getUiContext();
var textElem = drawBridge.drawText(context, {'x': 0, 'y': 0}, text, detailDrawStyles);
// then do the measure
textBox = drawBridge.measureDrawnText(context, textElem);
// remove textElem at last
drawBridge.removeDrawnElem(context, textElem);
}
var textPadding = (configs.getSpectrumDataPointDetailMarkerPadding() || 0) * unitLength;
var spaceings = {
'x1': contextCoord.x - spectrumClientBox.x1,
'x2': spectrumClientBox.x2 - contextCoord.x,
'y1': contextCoord.y - spectrumClientBox.y1,
'y2': spectrumClientBox.y2 - contextCoord.y
}
var textBoxXAlignment, textBoxYAlignment;
var textCoord = {};
if (spaceings.x2 - textPadding >= textBox.width)
{
textCoord.x = contextCoord.x + textPadding;
textBoxXAlignment = Kekule.Render.BoxXAlignment.LEFT;
}
else if (spaceings.x1 - textPadding >= textBox.width)
{
textCoord.x = contextCoord.x - textPadding;
textBoxXAlignment = Kekule.Render.BoxXAlignment.RIGHT;
}
else if (spaceings.x2 >= spaceings.x1)
{
textCoord.x = spectrumClientBox.x2 - textBox.width;
textBoxXAlignment = Kekule.Render.BoxXAlignment.LEFT;
}
else
{
textCoord.x = spectrumClientBox.x1 + textBox.width;
textBoxXAlignment = Kekule.Render.BoxXAlignment.RIGHT;
}
if (spaceings.y1 - textPadding >= textBox.height)
{
textCoord.y = contextCoord.y - textPadding;
textBoxYAlignment = Kekule.Render.BoxYAlignment.BOTTOM;
}
else if (spaceings.y2 - textPadding >= textBox.height)
{
textCoord.y = contextCoord.y + textPadding;
textBoxYAlignment = Kekule.Render.BoxYAlignment.TOP;
}
else if (spaceings.y1 >= spaceings.y2)
{
textCoord.y = spectrumClientBox.y1 + textBox.height;
textBoxYAlignment = Kekule.Render.BoxYAlignment.BOTTOM;
}
else
{
textCoord.y = spectrumClientBox.y2 - textBox.height;
textBoxYAlignment = Kekule.Render.BoxYAlignment.TOP;
}
detailDrawStyles.textBoxXAlignment = textBoxXAlignment;
detailDrawStyles.textBoxYAlignment = textBoxYAlignment;
}
//console.log(textCoord, textBoxXAlignment, textBoxYAlignment);
viewer.modifyTextBasedMarker(marker, textCoord, text, detailDrawStyles, false);
viewer.showUiMarker(marker, doRepaint);
}
},
/////////////////////////////////////
/**
* Reset the spectrum view settings.
*/
resetView: function()
{
this.changeHotTrackedDataItems(null, false);
this.changeSelectedDataItems(null, false);
this.resetViewportRange();
},
/** @private */
getSpectrumDataValueInfoFromIndependent: function(independentValues, candicateSections, extraOptions)
{
var spectrum = this.getSpectrum();
var sections = candicateSections || spectrum.getDisplayedDataSections() || [];
for (var i = 0, l = sections.length; i < l; ++i)
{
var sec = sections[i];
var v = sec.getDataValueFromIndependent(independentValues, extraOptions);
if (Kekule.ObjUtils.notUnset(v))
return {'value': v, 'section': sec};
}
return null;
},
/**
* Calculate values of dependant variable values from independent variable values.
* @param {Variant} independentValues A hash value with symbol: number map, or an array of values, or a single number value.
* @param {Hash} extraOptions
* @returns {Hash}
*/
calcValueFromIndependent: function(independentValues, extraOptions)
{
var indepHashValues = {};
if (typeof(independentValues) === 'number') // a direct number value,
indepHashValues = this._convArrayToSymboledHash([independentValues], this.getLocalVarSymbolsOfDependency(Kekule.VarDependency.INDEPENDENT));
else if (DataType.isArrayValue(independentValues))
indepHashValues = this._convArrayToSymboledHash(independentValues, this.getLocalVarSymbolsOfDependency(Kekule.VarDependency.INDEPENDENT));
else
indepHas