UNPKG

kekule

Version:

Open source JavaScript toolkit for chemoinformatics

1,435 lines (1,368 loc) 104 kB
/** * @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