diff --git a/package-lock.json b/package-lock.json index c940d70a4..5a1b92569 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.44.0", "license": "MIT", "dependencies": { - "@blueprintjs/core": "^5.3.3", + "@blueprintjs/core": "^5.5.1", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@lukeed/uuid": "^2.0.1", @@ -23,7 +23,7 @@ "file-saver": "^2.0.5", "filelist-utils": "^1.10.2", "formik": "^2.4.5", - "immer": "^10.0.2", + "immer": "^10.0.3", "jszip": "^3.10.1", "lodash": "^4.17.21", "ml-airpls": "^1.0.2", @@ -34,17 +34,17 @@ "ml-baseline-correction-regression": "^1.0.2", "ml-conrec": "^5.0.2", "ml-gsd": "^12.1.3", - "ml-matrix": "^6.10.5", - "ml-spectra-processing": "^12.5.1", + "ml-matrix": "^6.10.6", + "ml-spectra-processing": "^12.6.0", "ml-stat": "^1.3.3", "multiplet-analysis": "^2.1.2", "nmr-correlation": "^2.3.3", - "nmr-load-save": "^0.21.0", - "nmr-processing": "^11.1.1", + "nmr-load-save": "^0.22.2", + "nmr-processing": "^11.3.0", "nmredata": "^0.9.7", "numeral": "^2.0.6", - "openchemlib": "^8.5.0", - "openchemlib-utils": "^5.3.0", + "openchemlib": "^8.7.1", + "openchemlib-utils": "^5.4.0", "papaparse": "^5.4.1", "re-resizable": "6.9.11", "react-d3-utils": "^1.0.0", @@ -63,42 +63,43 @@ "react-transition-group": "^4.4.5", "react-use": "^17.4.0", "smart-array-filter": "^4.0.2", - "yup": "^1.3.1" + "yup": "^1.3.2" }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.23.0", "@babel/preset-react": "^7.22.15", - "@babel/preset-typescript": "^7.23.0", - "@playwright/test": "^1.38.1", + "@babel/preset-typescript": "^7.23.2", + "@playwright/test": "^1.39.0", "@simbathesailor/use-what-changed": "^2.0.0", - "@types/d3": "^7.4.1", - "@types/node": "^20.7.0", - "@types/papaparse": "^5.3.9", - "@types/react": "^18.2.23", - "@types/react-dom": "^18.2.8", - "@types/react-table": "^7.7.16", + "@types/d3": "^7.4.2", + "@types/lodash": "^4.14.200", + "@types/node": "^20.8.7", + "@types/papaparse": "^5.3.10", + "@types/react": "^18.2.29", + "@types/react-dom": "^18.2.14", + "@types/react-table": "^7.7.17", "@vitejs/plugin-react-swc": "^3.4.0", - "@vitest/coverage-v8": "^0.34.5", + "@vitest/coverage-v8": "^0.34.6", "cross-env": "^7.0.3", - "cspell": "^7.3.6", - "eslint": "^8.50.0", + "cspell": "^7.3.8", + "eslint": "^8.51.0", "eslint-config-cheminfo-react": "^10.0.0", "eslint-config-cheminfo-typescript": "^12.0.4", "modern-normalize": "^2.0.0", "postcss-styled-syntax": "^0.5.0", "prettier": "^3.0.3", - "rc-menu": "^9.12.0", + "rc-menu": "^9.12.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0", + "react-router-dom": "^6.17.0", "rimraf": "^5.0.5", "rollup-plugin-analyzer": "^4.0.0", "serve": "^14.2.1", - "stylelint": "^15.10.3", + "stylelint": "^15.11.0", "stylelint-config-standard": "^34.0.0", "typescript": "^5.2.2", - "vite": "^4.4.9", - "vitest": "^0.34.5" + "vite": "^4.5.0", + "vitest": "^0.34.6" }, "peerDependencies": { "react": ">=18.0.0", @@ -4500,14 +4501,15 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, "peer": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6078,9 +6080,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.560", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.560.tgz", - "integrity": "sha512-HhJH/pWAxTaPZl7R3mJ6gCd8MfjQdil9RAWk84qHaLsmPTadydfAmq0a1x8kZtOGQ6pZrWhOYj5uZ8I0meZIgg==", + "version": "1.4.561", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.561.tgz", + "integrity": "sha512-eS5t4ulWOBfVHdq9SW2dxEaFarj1lPjvJ8PaYMOjY0DecBaj/t4ARziL2IPpDr4atyWwjLFGQ2vo/VCgQFezVQ==", "dev": true, "peer": true }, @@ -9552,9 +9554,9 @@ } }, "node_modules/ml-matrix": { - "version": "6.10.6", - "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.10.6.tgz", - "integrity": "sha512-AZmwducQwGArUWW/C4Sv2g9Nwt08zBjz0V94NrXbMUZsEY820kJ+hUQ0gzNvTgGH1SaeKBq2ZtgWmfC7vFQ4mw==", + "version": "6.10.7", + "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.10.7.tgz", + "integrity": "sha512-v0AciHOXnCEYz8Dq4r5TeA+BFyIabBwng9y/rFVF43mhh3Ho2jDhJ6UZ0IUPRiedmfNcJDmI1j7YFdY30mHAcQ==", "dependencies": { "is-any-array": "^2.0.1", "ml-array-rescale": "^1.3.7" @@ -9856,29 +9858,29 @@ } }, "node_modules/nmr-load-save": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/nmr-load-save/-/nmr-load-save-0.21.0.tgz", - "integrity": "sha512-NePybxt/7G63cpnCuaMHsQSjfh61Ny8kPB1bpiONF9/ayOUfRgtvM0n5+M18arbQZ3x147nZR66JzLVduX+H8g==", + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/nmr-load-save/-/nmr-load-save-0.22.2.tgz", + "integrity": "sha512-vWz0DHsb5Nppr0AH0T+bEs6XVww20nHDuKzTFTsZL3cBgaHMR2qA8R6LSn4tgt6XH5zZ83Q6nWh5K2n7UkNuDA==", "dependencies": { "@lukeed/uuid": "^2.0.1", "@types/lodash.merge": "^4.6.7", - "brukerconverter": "^6.3.0", + "brukerconverter": "^6.3.1", "cheminfo-types": "^1.7.2", "convert-to-jcamp": "^5.4.9", - "filelist-utils": "^1.10.1", + "filelist-utils": "^1.10.2", "gyromagnetic-ratio": "^1.0.0", "is-any-array": "^2.0.1", - "jcampconverter": "^9.1.1", - "jeolconverter": "^1.0.1", + "jcampconverter": "^9.2.2", + "jeolconverter": "^1.0.2", "lodash.merge": "^4.6.2", - "ml-spectra-processing": "^12.5.0", + "ml-spectra-processing": "^12.5.1", "nmr-correlation": "^2.3.3", - "nmr-processing": "^11.0.1", - "nmredata": "^0.9.5", - "openchemlib": "^8.5.0", - "openchemlib-utils": "^5.2.0", + "nmr-processing": "^11.3.0", + "nmredata": "^0.9.7", + "openchemlib": "^8.7.0", + "openchemlib-utils": "^5.4.0", "sdf-parser": "^6.0.1", - "varian-converter": "^0.3.2" + "varian-converter": "^0.3.3" } }, "node_modules/nmr-processing": { @@ -10047,9 +10049,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", - "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "peer": true, "funding": { @@ -10892,14 +10894,14 @@ } }, "node_modules/rc-resize-observer": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.3.1.tgz", - "integrity": "sha512-iFUdt3NNhflbY3mwySv5CA1TC06zdJ+pfo0oc27xpf4PIOvfZwZGtD9Kz41wGYqC4SLio93RVAirSSpYlV/uYg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", "dev": true, "dependencies": { "@babel/runtime": "^7.20.7", "classnames": "^2.2.1", - "rc-util": "^5.27.0", + "rc-util": "^5.38.0", "resize-observer-polyfill": "^1.5.1" }, "peerDependencies": { @@ -12062,6 +12064,22 @@ "node": ">=8" } }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "peer": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -13768,14 +13786,14 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, "peer": true, "dependencies": { "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "call-bind": "^1.0.4", "for-each": "^0.3.3", "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" diff --git a/package.json b/package.json index 475eb42ec..d3edaa3c9 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "react-dom": ">=18.0.0" }, "dependencies": { - "@blueprintjs/core": "^5.3.3", + "@blueprintjs/core": "^5.5.1", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@lukeed/uuid": "^2.0.1", @@ -70,7 +70,7 @@ "file-saver": "^2.0.5", "filelist-utils": "^1.10.2", "formik": "^2.4.5", - "immer": "^10.0.2", + "immer": "^10.0.3", "jszip": "^3.10.1", "lodash": "^4.17.21", "ml-airpls": "^1.0.2", @@ -81,17 +81,17 @@ "ml-baseline-correction-regression": "^1.0.2", "ml-conrec": "^5.0.2", "ml-gsd": "^12.1.3", - "ml-matrix": "^6.10.5", - "ml-spectra-processing": "^12.5.1", + "ml-matrix": "^6.10.6", + "ml-spectra-processing": "^12.6.0", "ml-stat": "^1.3.3", "multiplet-analysis": "^2.1.2", "nmr-correlation": "^2.3.3", - "nmr-load-save": "^0.21.0", - "nmr-processing": "^11.1.1", + "nmr-load-save": "^0.22.2", + "nmr-processing": "^11.3.0", "nmredata": "^0.9.7", "numeral": "^2.0.6", - "openchemlib": "^8.5.0", - "openchemlib-utils": "^5.3.0", + "openchemlib": "^8.7.1", + "openchemlib-utils": "^5.4.0", "papaparse": "^5.4.1", "re-resizable": "6.9.11", "react-d3-utils": "^1.0.0", @@ -110,41 +110,42 @@ "react-transition-group": "^4.4.5", "react-use": "^17.4.0", "smart-array-filter": "^4.0.2", - "yup": "^1.3.1" + "yup": "^1.3.2" }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.23.0", "@babel/preset-react": "^7.22.15", - "@babel/preset-typescript": "^7.23.0", - "@playwright/test": "^1.38.1", + "@babel/preset-typescript": "^7.23.2", + "@playwright/test": "^1.39.0", "@simbathesailor/use-what-changed": "^2.0.0", - "@types/d3": "^7.4.1", - "@types/node": "^20.7.0", - "@types/papaparse": "^5.3.9", - "@types/react": "^18.2.23", - "@types/react-dom": "^18.2.8", - "@types/react-table": "^7.7.16", + "@types/d3": "^7.4.2", + "@types/lodash": "^4.14.200", + "@types/node": "^20.8.7", + "@types/papaparse": "^5.3.10", + "@types/react": "^18.2.29", + "@types/react-dom": "^18.2.14", + "@types/react-table": "^7.7.17", "@vitejs/plugin-react-swc": "^3.4.0", - "@vitest/coverage-v8": "^0.34.5", + "@vitest/coverage-v8": "^0.34.6", "cross-env": "^7.0.3", - "cspell": "^7.3.6", - "eslint": "^8.50.0", + "cspell": "^7.3.8", + "eslint": "^8.51.0", "eslint-config-cheminfo-react": "^10.0.0", "eslint-config-cheminfo-typescript": "^12.0.4", "modern-normalize": "^2.0.0", "postcss-styled-syntax": "^0.5.0", "prettier": "^3.0.3", - "rc-menu": "^9.12.0", + "rc-menu": "^9.12.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.16.0", + "react-router-dom": "^6.17.0", "rimraf": "^5.0.5", "rollup-plugin-analyzer": "^4.0.0", "serve": "^14.2.1", - "stylelint": "^15.10.3", + "stylelint": "^15.11.0", "stylelint-config-standard": "^34.0.0", "typescript": "^5.2.2", - "vite": "^4.4.9", - "vitest": "^0.34.5" + "vite": "^4.5.0", + "vitest": "^0.34.6" } } diff --git a/public/data/brukerFolders/alphaIonone.json b/public/data/brukerFolders/alphaIonone.json new file mode 100644 index 000000000..337da7da7 --- /dev/null +++ b/public/data/brukerFolders/alphaIonone.json @@ -0,0 +1,41 @@ +{ + "data": { + "spectra": [ + { + "sourceSelector": { + "files": [ + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/acqu2s", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/acqus", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/pdata/1/procs", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/pdata/1/proc2s", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/pdata/1/2rr", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/pdata/1/2ri", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/pdata/1/2ir", + "data/brukerFolders/alphaIonone.zip/alphaIonone/3/pdata/1/2ii" + ] + }, + "filters": [], + "display": { + "isPositiveVisible": true, + "isNegativeVisible": true, + "isVisible": true, + "dimension": 2 + }, + "zones": { + "values": [], + "options": {} + } + } + ], + "molecules": [], + "source": { + "baseURL": "", + "entries": [ + { + "relativePath": "data/brukerFolders/alphaIonone.zip" + } + ] + } + }, + "version": 4 +} \ No newline at end of file diff --git a/public/data/brukerFolders/alphaIonone.zip b/public/data/brukerFolders/alphaIonone.zip new file mode 100644 index 000000000..a64c70132 Binary files /dev/null and b/public/data/brukerFolders/alphaIonone.zip differ diff --git a/src/component/1d-2d/tools/BrushX.tsx b/src/component/1d-2d/tools/BrushX.tsx index fca3af36f..5cedb9b64 100644 --- a/src/component/1d-2d/tools/BrushX.tsx +++ b/src/component/1d-2d/tools/BrushX.tsx @@ -10,6 +10,7 @@ const styles: Record<'container', CSSProperties> = { position: 'absolute', top: '0px', left: '0px', + zIndex: 9, }, }; diff --git a/src/component/1d-2d/tools/BrushXY.tsx b/src/component/1d-2d/tools/BrushXY.tsx index ece9b5d5b..a58d144f5 100644 --- a/src/component/1d-2d/tools/BrushXY.tsx +++ b/src/component/1d-2d/tools/BrushXY.tsx @@ -11,6 +11,7 @@ const styles: Record<'container', CSSProperties> = { top: '0px', left: '0px', zoom: '100%', + zIndex: 9, }, }; @@ -21,6 +22,7 @@ const allowTools = new Set([ options.peakPicking.id, options.integral.id, options.phaseCorrection.id, + options.phaseCorrectionTwoDimensions.id, options.baselineCorrection.id, options.rangePicking.id, options.zonePicking.id, diff --git a/src/component/1d-2d/tools/CrossLinePointer.tsx b/src/component/1d-2d/tools/CrossLinePointer.tsx index c6407323d..08ca23218 100644 --- a/src/component/1d-2d/tools/CrossLinePointer.tsx +++ b/src/component/1d-2d/tools/CrossLinePointer.tsx @@ -20,6 +20,7 @@ const allowTools = new Set([ options.apodization.id, options.equalizer.id, options.baselineCorrection.id, + options.phaseCorrectionTwoDimensions.id, options.zonePicking.id, options.slicing.id, options.integral.id, @@ -68,6 +69,7 @@ function CrossLinePointer() { overflow: 'visible', width: 2 * width, height: 2 * height, + zIndex: 9, }} > diff --git a/src/component/1d/Chart1D.tsx b/src/component/1d/Chart1D.tsx index efbcbd782..c68dc0f47 100644 --- a/src/component/1d/Chart1D.tsx +++ b/src/component/1d/Chart1D.tsx @@ -14,6 +14,7 @@ import { PeakEditionProvider } from './peaks/PeakEditionManager'; import Peaks from './peaks/Peaks'; import PeaksShapes from './peaks/PeaksShapes'; import Ranges from './ranges/Ranges'; +import RangesIntegrals from './ranges/RangesIntegrals'; import BaseLineZones from './tool/BaseLineZones'; function Chart1D({ mode, width, height, margin, displayerKey }) { @@ -45,6 +46,7 @@ function Chart1D({ mode, width, height, margin, displayerKey }) { + diff --git a/src/component/1d/Viewer1D.tsx b/src/component/1d/Viewer1D.tsx index cf9733865..2d428545a 100644 --- a/src/component/1d/Viewer1D.tsx +++ b/src/component/1d/Viewer1D.tsx @@ -290,30 +290,30 @@ function Viewer1D({ emptyText = undefined }: Viewer1DProps) { const handleZoom = useCallback( (event) => { - dispatch({ type: 'SET_ZOOM', payload: { event, selectedTool } }); + dispatch({ type: 'SET_ZOOM', payload: { event } }); }, - [dispatch, selectedTool], + [dispatch], ); const mouseClick = useCallback( - (position) => { + (event) => { if (!scaleState.scaleX) return; - const xPPM = scaleState.scaleX().invert(position.x); + const xPPM = scaleState.scaleX().invert(event.x); const propagateEvent = () => { Events.emit('mouseClick', { - ...position, + ...event, xPPM, }); }; - if (position.shiftKey) { + if (event.shiftKey) { switch (selectedTool) { case options.peakPicking.id: dispatch({ type: 'ADD_PEAK', - payload: position, + payload: event, }); break; case options.editRange.id: @@ -331,20 +331,21 @@ function Viewer1D({ emptyText = undefined }: Viewer1DProps) { payload: { cutValue: xPPM }, }); break; - default: - break; - } - } else { - switch (selectedTool) { + case options.phaseCorrection.id: dispatch({ - type: 'SET_VERTICAL_INDICATOR_X_POSITION', + type: 'SET_ONE_DIMENSION_PIVOT_POINT', payload: { - position: position.x, + value: event.x, }, }); - break; + break; + default: + break; + } + } else { + switch (selectedTool) { default: } } diff --git a/src/component/1d/integral/IntegralsSeries.tsx b/src/component/1d/integral/IntegralsSeries.tsx index 1cd31cf40..219637d7f 100644 --- a/src/component/1d/integral/IntegralsSeries.tsx +++ b/src/component/1d/integral/IntegralsSeries.tsx @@ -1,20 +1,45 @@ +import { xyIntegral, xyMaxY } from 'ml-spectra-processing'; import { Spectrum1D } from 'nmr-load-save'; +import { Integral as IntegralType } from 'nmr-processing'; import { useChartData } from '../../context/ChartContext'; - -import Integral from './Integral'; import useSpectrum from '../../hooks/useSpectrum'; +import { Integration } from './Integration'; + const emptyData = { integrals: {}, info: {}, display: {} }; -function IntegralsSeries() { +export interface IntegralData extends IntegralType { + x: Float64Array; + y: Float64Array; +} + +export default function IntegralsSeries() { const { displayerKey, view: { spectra: { activeTab: nucleus }, }, } = useChartData(); + const integrals = useIntegrals(); + + if (!integrals) return null; + + return ( + + {integrals.values.map((integral) => ( + + ))} + + ); +} +function useIntegrals() { const spectrum = useSpectrum(emptyData) as Spectrum1D; if ( @@ -25,15 +50,27 @@ function IntegralsSeries() { return null; } - return ( - - - {spectrum.integrals.values.map((integral) => ( - - ))} - - - ); -} + let max = Number.NEGATIVE_INFINITY; + const values: IntegralData[] = []; -export default IntegralsSeries; + const { + data: { x, re }, + integrals, + } = spectrum; + for (const integral of integrals?.values || []) { + const { from, to } = integral; + const integralData = xyIntegral( + { x, y: re }, + { + from, + to, + reverse: true, + }, + ); + values.push({ ...integral, ...integralData } as IntegralData); + const value = xyMaxY(integralData); + if (value > max) max = value; + } + + return { max, values }; +} diff --git a/src/component/1d/integral/Integral.tsx b/src/component/1d/integral/Integration.tsx similarity index 60% rename from src/component/1d/integral/Integral.tsx rename to src/component/1d/integral/Integration.tsx index 90981aa4d..e4ee53496 100644 --- a/src/component/1d/integral/Integral.tsx +++ b/src/component/1d/integral/Integration.tsx @@ -1,17 +1,20 @@ -import { Integral as IntegralType } from 'nmr-processing'; - +import { useActiveSpectrumIntegralsViewState } from '../../hooks/useActiveSpectrumIntegralsViewState'; import useIntegralPath from '../../hooks/useIntegralPath'; import { usePanelPreferences } from '../../hooks/usePanelPreferences'; import IntegralResizable from './IntegralResizable'; +import { IntegralData } from './IntegralsSeries'; interface IntegralProps { - integral: IntegralType; + integral: IntegralData; nucleus: string; + max: number; } -function Integral({ integral, nucleus }: IntegralProps) { - const path = useIntegralPath(integral); +export function Integration({ integral, nucleus, max }: IntegralProps) { + const { x, y } = integral; + const { scaleRatio } = useActiveSpectrumIntegralsViewState(); + const path = useIntegralPath({ x, y, max, scaleRatio }); const integralPreferences = usePanelPreferences('integrals', nucleus); return ( @@ -31,5 +34,3 @@ function Integral({ integral, nucleus }: IntegralProps) { ); } - -export default Integral; diff --git a/src/component/1d/peaks/PeakAnnotationsSpreadMode.tsx b/src/component/1d/peaks/PeakAnnotationsSpreadMode.tsx index a54b1f79f..f96dbb964 100644 --- a/src/component/1d/peaks/PeakAnnotationsSpreadMode.tsx +++ b/src/component/1d/peaks/PeakAnnotationsSpreadMode.tsx @@ -1,16 +1,17 @@ +import { memo } from 'react'; + import { useHighlight } from '../../highlight'; import { formatNumber } from '../../utility/formatNumber'; +import { getDecimalsCount } from '../utilities/getDecimalsCount'; import { resolve } from '../utilities/intersectionResolver'; import { PeakEditionListener } from './PeakEditionManager'; -import { getDecimalsCount } from '../utilities/getDecimalsCount'; import { PeaksAnnotationsProps, PeaksSource, getHighlightExtraId, getHighlightSource, } from './Peaks'; -import { memo } from 'react'; const notationWidth = 10; const notationMargin = 2; diff --git a/src/component/1d/peaks/PeakEditionManager.tsx b/src/component/1d/peaks/PeakEditionManager.tsx index 3ba0c0e86..99bc8711d 100644 --- a/src/component/1d/peaks/PeakEditionManager.tsx +++ b/src/component/1d/peaks/PeakEditionManager.tsx @@ -12,8 +12,8 @@ import * as Yup from 'yup'; import { useChartData } from '../../context/ChartContext'; import { useDispatch } from '../../context/DispatchContext'; import { useScaleChecked } from '../../context/ScaleContext'; -import { useActiveSpectrum } from '../../hooks/useActiveSpectrum'; import FormikInput from '../../elements/formik/FormikInput'; +import { useActiveSpectrum } from '../../hooks/useActiveSpectrum'; const validationSchema = Yup.object({ value: Yup.number().required(), diff --git a/src/component/1d/peaks/Peaks.tsx b/src/component/1d/peaks/Peaks.tsx index 7b9ff9673..8992857b2 100644 --- a/src/component/1d/peaks/Peaks.tsx +++ b/src/component/1d/peaks/Peaks.tsx @@ -1,16 +1,16 @@ import { Spectrum1D } from 'nmr-load-save'; +import { NMRPeak1D, Peak1D, Range } from 'nmr-processing'; +import { memo, useMemo } from 'react'; import { useChartData } from '../../context/ChartContext'; import { useActiveSpectrumPeaksViewState } from '../../hooks/useActiveSpectrumPeaksViewState'; +import { useActiveSpectrumRangesViewState } from '../../hooks/useActiveSpectrumRangesViewState'; +import { usePanelPreferences } from '../../hooks/usePanelPreferences'; import useSpectrum from '../../hooks/useSpectrum'; +import { useScaleX } from '../utilities/scale'; import PeakAnnotations from './PeakAnnotations'; import PeakAnnotationsSpreadMode from './PeakAnnotationsSpreadMode'; -import { NMRPeak1D, Peak1D, Range } from 'nmr-processing'; -import { memo, useMemo } from 'react'; -import { useScaleX } from '../utilities/scale'; -import { usePanelPreferences } from '../../hooks/usePanelPreferences'; -import { useActiveSpectrumRangesViewState } from '../../hooks/useActiveSpectrumRangesViewState'; interface Peak1DWithParentKeys extends Peak1D { parentKeys?: string[]; diff --git a/src/component/1d/ranges/RangeIntegral.tsx b/src/component/1d/ranges/RangeIntegral.tsx deleted file mode 100644 index e75faf778..000000000 --- a/src/component/1d/ranges/RangeIntegral.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import useIntegralPath from '../../hooks/useIntegralPath'; - -interface IntegralProps { - range: { id: string; from: number; to: number; integral?: number }; -} - -function RangeIntegral({ range }: IntegralProps) { - const path = useIntegralPath(range); - - return ( - - ); -} - -export default RangeIntegral; diff --git a/src/component/1d/ranges/Ranges.tsx b/src/component/1d/ranges/Ranges.tsx index 16648b219..c509d6784 100644 --- a/src/component/1d/ranges/Ranges.tsx +++ b/src/component/1d/ranges/Ranges.tsx @@ -1,6 +1,6 @@ import { Spectrum1D } from 'nmr-load-save'; import { Ranges as RangesProps } from 'nmr-processing'; -import { Fragment, memo } from 'react'; +import { memo } from 'react'; import { useChartData } from '../../context/ChartContext'; import { useActiveSpectrumRangesViewState } from '../../hooks/useActiveSpectrumRangesViewState'; @@ -8,14 +8,12 @@ import { usePanelPreferences } from '../../hooks/usePanelPreferences'; import useSpectrum from '../../hooks/useSpectrum'; import Range from './Range'; -import RangeIntegral from './RangeIntegral'; interface RangesInnerProps { displayerKey: string; selectedTool: string; ranges: RangesProps; showMultiplicityTrees: boolean; - showRangesIntegrals: boolean; relativeFormat: string; } @@ -24,21 +22,18 @@ function RangesInner({ displayerKey, selectedTool, showMultiplicityTrees, - showRangesIntegrals, relativeFormat, }: RangesInnerProps) { return ( {ranges?.values?.map((range) => ( - - - {showRangesIntegrals && } - + ))} ); @@ -56,7 +51,7 @@ export default function Ranges() { }, toolOptions: { selectedTool }, } = useChartData(); - const { showMultiplicityTrees, showRangesIntegrals } = + const { showMultiplicityTrees, showIntegrals } = useActiveSpectrumRangesViewState(); const spectrum = useSpectrum(emptyData) as Spectrum1D; const rangesPreferences = usePanelPreferences('ranges', activeTab); @@ -74,7 +69,7 @@ export default function Ranges() { ranges={spectrum.ranges} {...{ showMultiplicityTrees, - showRangesIntegrals, + showIntegrals, selectedTool, displayerKey, relativeFormat: rangesPreferences.relative.format, diff --git a/src/component/1d/ranges/RangesIntegrals.tsx b/src/component/1d/ranges/RangesIntegrals.tsx new file mode 100644 index 000000000..d0bbc3792 --- /dev/null +++ b/src/component/1d/ranges/RangesIntegrals.tsx @@ -0,0 +1,91 @@ +import { xyIntegral, xyMaxY } from 'ml-spectra-processing'; +import { Spectrum1D } from 'nmr-load-save'; + +import { useChartData } from '../../context/ChartContext'; +import { useActiveSpectrumRangesViewState } from '../../hooks/useActiveSpectrumRangesViewState'; +import useIntegralPath from '../../hooks/useIntegralPath'; +import useSpectrum from '../../hooks/useSpectrum'; + +interface IntegralData { + x: Float64Array; + y: Float64Array; + // eslint-disable-next-line react/no-unused-prop-types + id: string; +} + +interface IntegralProps extends IntegralData { + max: number; +} + +function Integral(props: IntegralProps) { + const { x, y, max } = props; + const { integralsScaleRatio } = useActiveSpectrumRangesViewState(); + const path = useIntegralPath({ x, y, max, scaleRatio: integralsScaleRatio }); + + return ( + + ); +} + +const emptyData = { ranges: {}, info: {}, display: {} }; + +function RangesIntegrals() { + const { displayerKey } = useChartData(); + const spectrum = useSpectrum(emptyData) as Spectrum1D; + const integrals = useIntegrals(); + if ( + !spectrum.ranges?.values || + !spectrum.display.isVisible || + spectrum.info?.isFid || + !integrals + ) { + return null; + } + + return ( + + {integrals.values.map((integral) => { + return ; + })} + + ); +} + +function useIntegrals() { + const spectrum = useSpectrum() as Spectrum1D; + const { showIntegrals } = useActiveSpectrumRangesViewState(); + + if (!spectrum || !showIntegrals) return; + + let max = Number.NEGATIVE_INFINITY; + const values: IntegralData[] = []; + + const { + data: { x, re }, + ranges, + } = spectrum; + for (const range of ranges?.values || []) { + const { from, to, id } = range; + const integral = xyIntegral( + { x, y: re }, + { + from, + to, + reverse: true, + }, + ); + values.push({ ...integral, id } as IntegralData); + const value = xyMaxY(integral); + if (value > max) max = value; + } + + return { max, values }; +} + +export default RangesIntegrals; diff --git a/src/component/1d/tool/XLabelPointer.tsx b/src/component/1d/tool/XLabelPointer.tsx index 1725f7ce2..548a97083 100644 --- a/src/component/1d/tool/XLabelPointer.tsx +++ b/src/component/1d/tool/XLabelPointer.tsx @@ -1,12 +1,12 @@ import { Spectrum1D } from 'nmr-load-save'; -import { useCallback, useMemo, CSSProperties } from 'react'; +import { useCallback, CSSProperties } from 'react'; import { useBrushTracker } from '../../EventsTrackers/BrushTracker'; import { useMouseTracker } from '../../EventsTrackers/MouseTracker'; import { useChartData } from '../../context/ChartContext'; import { useScaleChecked } from '../../context/ScaleContext'; -import { useActiveSpectrum } from '../../hooks/useActiveSpectrum'; import { useFormatNumberByNucleus } from '../../hooks/useFormatNumberByNucleus'; +import useSpectrum from '../../hooks/useSpectrum'; const style: CSSProperties = { cursor: 'crosshair', @@ -20,31 +20,25 @@ const style: CSSProperties = { }; function XLabelPointer() { - const { height, width, margin, data } = useChartData(); - const activeSpectrum = useActiveSpectrum(); + const { height, width, margin } = useChartData(); + const activeSpectrum = useSpectrum(null); const { scaleX } = useScaleChecked(); const position = useMouseTracker(); const brushState = useBrushTracker(); - const activeSpectrumData = useMemo(() => { - const spectrumData = activeSpectrum - ? data.find((d) => d.id === activeSpectrum.id) - : null; - return spectrumData; - }, [activeSpectrum, data]); const format = useFormatNumberByNucleus( - (activeSpectrumData as Spectrum1D)?.info.nucleus, + (activeSpectrum as Spectrum1D)?.info.nucleus, ); const getXValue = useCallback( (xVal) => { - if (activeSpectrumData) { + if (activeSpectrum) { const xInvert = scaleX().invert(xVal); return format(xInvert); } }, - [activeSpectrumData, format, scaleX], + [activeSpectrum, format, scaleX], ); if ( diff --git a/src/component/1d/utilities/scale.ts b/src/component/1d/utilities/scale.ts index e4ca1570c..14584c2b3 100644 --- a/src/component/1d/utilities/scale.ts +++ b/src/component/1d/utilities/scale.ts @@ -1,14 +1,14 @@ import { scaleLinear, zoomIdentity } from 'd3'; +import { useCallback } from 'react'; + +import { useChartData } from '../../context/ChartContext'; +import { useVerticalAlign } from '../../hooks/useVerticalAlign'; import { - ActiveSpectrum, Domains, Margin, SpectraDirection, VerticalAlignment, } from '../../reducer/Reducer'; -import { useChartData } from '../../context/ChartContext'; -import { useCallback } from 'react'; -import { useVerticalAlign } from '../../hooks/useVerticalAlign'; interface ScaleXOptions { width: number; @@ -58,20 +58,16 @@ function getYScale( interface IntegralYScaleOptions { height: number; margin: Margin; - integralsYDomains: Domains; - activeSpectrum: ActiveSpectrum | null; - verticalAlign: VerticalAlignment; + yDomain: number[]; + scaleRatio: number; } function getIntegralYScale(options: IntegralYScaleOptions) { - const { height, margin, verticalAlign, integralsYDomains, activeSpectrum } = - options; - const _height = verticalAlign === 'center' ? height / 2 : height; + const { height, margin, yDomain, scaleRatio } = options; + const [min, max] = yDomain; return scaleLinear( - activeSpectrum?.id && integralsYDomains?.[activeSpectrum?.id] - ? integralsYDomains[activeSpectrum?.id] - : [0, 0], - [_height * 0.3, margin.top + _height * 0.1], + [min * scaleRatio, max * scaleRatio], + [height * 0.3, margin.top + height * 0.1], ); } diff --git a/src/component/2d/1d-tracer/HorizontalSliceChart.tsx b/src/component/2d/1d-tracer/HorizontalSliceChart.tsx index fd7508c21..62f07eb0a 100644 --- a/src/component/2d/1d-tracer/HorizontalSliceChart.tsx +++ b/src/component/2d/1d-tracer/HorizontalSliceChart.tsx @@ -25,7 +25,7 @@ function usePath(data: NmrData1D, options: UsePathOptions) { const { x, re: y } = data; - const scaleY = getSliceYScale(y, height, mode, vericalMargin); + const scaleY = getSliceYScale(y, height, mode, { margin: vericalMargin }); const pathBuilder = new PathBuilder(); pathBuilder.moveTo(scaleX(x[0]), scaleY(y[0])); diff --git a/src/component/2d/1d-tracer/VerticalSliceChart.tsx b/src/component/2d/1d-tracer/VerticalSliceChart.tsx index f8b223fc6..eef7d4bd4 100644 --- a/src/component/2d/1d-tracer/VerticalSliceChart.tsx +++ b/src/component/2d/1d-tracer/VerticalSliceChart.tsx @@ -24,7 +24,7 @@ function usePath(data, props: usePathOptions) { const { x, re: y } = data; - const scaleY = getSliceYScale(y, width, mode, horizontalMargin); + const scaleY = getSliceYScale(y, width, mode, { margin: horizontalMargin }); const pathBuilder = new PathBuilder(); @@ -50,7 +50,7 @@ function VerticalSliceChart(props: VerticalSliceChartProps) { - + diff --git a/src/component/2d/1d-tracer/phase-correction-traces/PhaseTraceWithMouse.tsx b/src/component/2d/1d-tracer/phase-correction-traces/PhaseTraceWithMouse.tsx new file mode 100644 index 000000000..95fc67e83 --- /dev/null +++ b/src/component/2d/1d-tracer/phase-correction-traces/PhaseTraceWithMouse.tsx @@ -0,0 +1,44 @@ +import { Spectrum2D } from 'nmr-load-save'; + +import { getSlice } from '../../../../data/data2d/Spectrum2D'; +import { useMouseTracker } from '../../../EventsTrackers/MouseTracker'; +import { useChartData } from '../../../context/ChartContext'; +import { useActiveSpectrum } from '../../../hooks/useActiveSpectrum'; +import { useScale2DX, useScale2DY } from '../../utilities/scale'; + +import { SpectrumPhaseTrace } from './SpectrumPhaseTrace'; +import { useActivePhaseTraces } from './useActivePhaseTraces'; + +export function PhaseTraceWithMouse() { + const { width, height, data: spectra } = useChartData(); + const activeSpectrum = useActiveSpectrum(); + const { activeTraceDirection, color } = useActivePhaseTraces(); + const position = useMouseTracker(); + + const scale2dX = useScale2DX(); + const scale2dY = useScale2DY(); + + if (!position || !width || !height || !activeSpectrum?.id) { + return null; + } + const spectrum = spectra[activeSpectrum.index] as Spectrum2D; + + const sliceData = getSlice(spectrum, { + x: scale2dX.invert(position.x), + y: scale2dY.invert(position.y), + }); + + const data = sliceData?.[activeTraceDirection]?.data; + if (!data) { + return null; + } + + return ( + + ); +} diff --git a/src/component/2d/1d-tracer/phase-correction-traces/PhaseTraces.tsx b/src/component/2d/1d-tracer/phase-correction-traces/PhaseTraces.tsx new file mode 100644 index 000000000..55b6b623a --- /dev/null +++ b/src/component/2d/1d-tracer/phase-correction-traces/PhaseTraces.tsx @@ -0,0 +1,42 @@ +import { useChartData } from '../../../context/ChartContext'; +import { useActiveSpectrum } from '../../../hooks/useActiveSpectrum'; + +import { PhaseTraceWithMouse } from './PhaseTraceWithMouse'; +import { SpectraPhaseTraces } from './SpectraPhaseTraces'; + +export function PhaseTraces() { + const { width, height, margin, displayerKey } = useChartData(); + const activeSpectrum = useActiveSpectrum(); + + if (!activeSpectrum?.id) return null; + + const clipWidth = width - margin.left - margin.right; + const clipHeight = height - margin.top - margin.bottom; + + return ( + + + + + + + + + + + + ); +} diff --git a/src/component/2d/1d-tracer/phase-correction-traces/SpectraPhaseTraces.tsx b/src/component/2d/1d-tracer/phase-correction-traces/SpectraPhaseTraces.tsx new file mode 100644 index 000000000..ccd248cf8 --- /dev/null +++ b/src/component/2d/1d-tracer/phase-correction-traces/SpectraPhaseTraces.tsx @@ -0,0 +1,102 @@ +/** @jsxImportSource @emotion/react */ +import { css } from '@emotion/react'; + +import { useChartData } from '../../../context/ChartContext'; +import { HighlightEventSource, useHighlight } from '../../../highlight'; +import { SpectrumTrace, TraceDirection } from '../../../reducer/Reducer'; +import { useScale2DX, useScale2DY } from '../../utilities/scale'; + +import { SpectrumPhaseTrace } from './SpectrumPhaseTrace'; +import { useActivePhaseTraces } from './useActivePhaseTraces'; + +const BOX_SIZE = 20; + +const style = css` + .target { + fill: transparent; + } + + &:hover { + .target { + fill: #ff6f0057; + } + } +`; + +export function SpectraPhaseTraces() { + const { width, height } = useChartData(); + const { spectra = [], color, activeTraceDirection } = useActivePhaseTraces(); + + if (!width || !height || spectra.length === 0) { + return null; + } + + return spectra.map((spectrumTrace) => { + return ( + + ); + }); +} + +interface SpectrumTraceProps { + spectrum: SpectrumTrace; + color: string; + direction: TraceDirection; +} + +function PhaseTrace(props: SpectrumTraceProps) { + const { width, height, margin } = useChartData(); + + const { + spectrum: { data, x, y, id }, + color, + direction, + } = props; + const highligh = useHighlight([id], { + type: HighlightEventSource.PHASE_CORRECTION_TRACE, + extra: { id }, + }); + + const scale2dX = useScale2DX(); + const scale2dY = useScale2DY(); + + const innerheight = height - margin.top - margin.bottom; + const innerWidth = width - margin.left - margin.right; + const transformY = innerheight - BOX_SIZE / 2; + const transformX = innerWidth - BOX_SIZE / 2; + + return ( + + {direction === 'horizontal' && ( + + )} + {direction === 'vertical' && ( + + )} + + ); +} diff --git a/src/component/2d/1d-tracer/phase-correction-traces/SpectrumPhaseTrace.tsx b/src/component/2d/1d-tracer/phase-correction-traces/SpectrumPhaseTrace.tsx new file mode 100644 index 000000000..9fe94b9de --- /dev/null +++ b/src/component/2d/1d-tracer/phase-correction-traces/SpectrumPhaseTrace.tsx @@ -0,0 +1,89 @@ +import { ReactNode } from 'react'; + +import { useChartData } from '../../../context/ChartContext'; +import { TraceDirection } from '../../../reducer/Reducer'; +import { PathBuilder } from '../../../utility/PathBuilder'; +import { + get2DXScale, + get2DYScale, + getSliceYScale, +} from '../../utilities/scale'; + +import { useActivePhaseTraces } from './useActivePhaseTraces'; + +interface SpectrumPhaseTraceProps extends React.SVGAttributes { + data: { x: Float64Array; re: Float64Array }; + position: { x: number; y: number }; + color: string; + direction: TraceDirection; + children?: ReactNode; +} + +function usePath(x: Float64Array, y: Float64Array, direction: TraceDirection) { + const { width, margin, height, xDomain, yDomain, mode } = useChartData(); + const { scaleRatio } = useActivePhaseTraces(); + + if (direction === 'horizontal') { + const scaleX = get2DXScale({ margin, width, xDomain, mode }); + const scaleY = getSliceYScale(y, height, 'RTL', { + margin: margin.top + margin.bottom, + scaleRatio, + }); + + const pathBuilder = new PathBuilder(); + pathBuilder.moveTo(scaleX(x[0]), scaleY(y[0])); + for (let i = 1; i < x.length; i++) { + pathBuilder.lineTo(scaleX(x[i]), scaleY(y[i])); + } + + return pathBuilder.toString(); + } + + const scaleX = get2DYScale({ margin, height, yDomain }); + const scaleY = getSliceYScale(y, width, 'RTL', { + margin: margin.left + margin.right, + scaleRatio, + }); + + const pathBuilder = new PathBuilder(); + + pathBuilder.moveTo(scaleY(y.at(-1) as number), scaleX(x.at(-1) as number)); + + for (let i = x.length - 2; i >= 0; i--) { + pathBuilder.lineTo(scaleY(y[i]), scaleX(x[i])); + } + + return pathBuilder.toString(); +} + +export function SpectrumPhaseTrace(props: SpectrumPhaseTraceProps) { + const { data, position, color, direction, children, ...othersProps } = props; + const { width, margin, height } = useChartData(); + + const { x, re } = data; + const path = usePath(x, re, direction); + const innerheight = height - margin.top - margin.bottom; + const innerWidth = width - margin.left - margin.right; + + const translateY = direction === 'horizontal' ? position.y - innerheight : 0; + const translateX = direction === 'vertical' ? position.x - innerWidth : 0; + + return ( + + + {children} + + ); +} diff --git a/src/component/2d/1d-tracer/phase-correction-traces/index.ts b/src/component/2d/1d-tracer/phase-correction-traces/index.ts new file mode 100644 index 000000000..b0e25c9df --- /dev/null +++ b/src/component/2d/1d-tracer/phase-correction-traces/index.ts @@ -0,0 +1 @@ +export { PhaseTraces } from './PhaseTraces'; diff --git a/src/component/2d/1d-tracer/phase-correction-traces/useActivePhaseTraces.ts b/src/component/2d/1d-tracer/phase-correction-traces/useActivePhaseTraces.ts new file mode 100644 index 000000000..381a28ac0 --- /dev/null +++ b/src/component/2d/1d-tracer/phase-correction-traces/useActivePhaseTraces.ts @@ -0,0 +1,18 @@ +import { COLORS } from '../../../../data/utilities/generateColor'; +import { useChartData } from '../../../context/ChartContext'; + +export function useActivePhaseTraces() { + const { + toolOptions: { + data: { + twoDimensionPhaseCorrection: { traces, activeTraceDirection }, + }, + }, + } = useChartData(); + const color = activeTraceDirection === 'horizontal' ? COLORS[0] : COLORS[1]; + return { + ...traces[activeTraceDirection], + activeTraceDirection, + color, + }; +} diff --git a/src/component/2d/Chart2D.tsx b/src/component/2d/Chart2D.tsx index 9a0f44a9c..7f0bc545b 100644 --- a/src/component/2d/Chart2D.tsx +++ b/src/component/2d/Chart2D.tsx @@ -40,6 +40,7 @@ function chart2DInner({ height={height} id="nmrSVG" shapeRendering={SpectraRendering} + style={{ position: 'absolute' }} > diff --git a/src/component/2d/SlicingView.tsx b/src/component/2d/SlicingView.tsx index 09fafafc6..4e9bd4985 100644 --- a/src/component/2d/SlicingView.tsx +++ b/src/component/2d/SlicingView.tsx @@ -38,6 +38,7 @@ function SlicingView() { height={height} style={{ position: 'absolute', + zIndex: 1, backgroundColor: 'rgba(255,255,255,0.8)', }} > diff --git a/src/component/2d/Viewer2D.tsx b/src/component/2d/Viewer2D.tsx index 91c25c104..2b96d7525 100644 --- a/src/component/2d/Viewer2D.tsx +++ b/src/component/2d/Viewer2D.tsx @@ -16,9 +16,11 @@ import { useDispatch } from '../context/DispatchContext'; import Spinner from '../loader/Spinner'; import { options } from '../toolbar/ToolTypes'; +import { PhaseTraces } from './1d-tracer/phase-correction-traces'; import Chart2D from './Chart2D'; import FooterBanner from './FooterBanner'; import SlicingView from './SlicingView'; +import PivotIndicator from './tools/PivotIndicator'; import XYLabelPointer from './tools/XYLabelPointer'; import { get2DDimensionLayout, getLayoutID } from './utilities/DimensionLayout'; import { get2DXScale, get2DYScale } from './utilities/scale'; @@ -138,28 +140,47 @@ function Viewer2D({ emptyText = undefined }: Viewer2DProps) { ); const handleZoom: OnZoom = (event) => { - const { x: startX, y: startY } = event; + const { x: startX, y: startY, shiftKey } = event; const trackID = getLayoutID(DIMENSION, { startX, startY }); if (trackID) { - if (trackID === 'CENTER_2D') { - dispatch({ type: 'SET_2D_LEVEL', payload: event }); - } else { + if ( + trackID !== 'CENTER_2D' || + (selectedTool === 'phaseCorrectionTwoDimensions' && !shiftKey) + ) { dispatch({ type: 'SET_ZOOM', payload: { event, trackID } }); + } else { + dispatch({ type: 'SET_2D_LEVEL', payload: event }); } } }; const mouseClick: OnClick = useCallback( - (position) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { x, y } = position; - switch (selectedTool) { - default: - break; + (event) => { + const { x, y, shiftKey } = event; + + if (shiftKey) { + switch (selectedTool) { + case 'phaseCorrectionTwoDimensions': + dispatch({ + type: 'SET_TWO_DIMENSION_PIVOT_POINT', + payload: { x, y }, + }); + break; + default: + break; + } + } else { + switch (selectedTool) { + case 'phaseCorrectionTwoDimensions': + dispatch({ type: 'ADD_PHASE_CORRECTION_TRACE', payload: { x, y } }); + break; + default: + break; + } } }, - [selectedTool], + [selectedTool, dispatch], ); return ( @@ -183,11 +204,15 @@ function Viewer2D({ emptyText = undefined }: Viewer2DProps) { }} > {selectedTool && selectedTool === options.slicing.id && ( )} + {selectedTool && + selectedTool === options.phaseCorrectionTwoDimensions.id && ( + + )} @@ -212,6 +237,7 @@ function Viewer2D({ emptyText = undefined }: Viewer2DProps) { /> )} + diff --git a/src/component/2d/tools/PivotIndicator.tsx b/src/component/2d/tools/PivotIndicator.tsx new file mode 100644 index 000000000..08c66cc3f --- /dev/null +++ b/src/component/2d/tools/PivotIndicator.tsx @@ -0,0 +1,65 @@ +import { CSSProperties } from 'react'; + +import { useChartData } from '../../context/ChartContext'; +import { TraceDirection } from '../../reducer/Reducer'; +import { options } from '../../toolbar/ToolTypes'; +import { useActivePhaseTraces } from '../1d-tracer/phase-correction-traces/useActivePhaseTraces'; +import { get2DXScale, get2DYScale } from '../utilities/scale'; + +function getStyle(direction: TraceDirection, translate: number) { + const base: CSSProperties = { + transformOrigin: 'top left', + position: 'absolute', + top: '0px', + left: '0px', + backgroundColor: 'black', + zIndex: 9, + }; + if (direction === 'horizontal') { + return { + ...base, + width: '1px', + height: '100%', + transform: `translateX(${translate}px)`, + }; + } + + return { + ...base, + width: '100%', + height: '1px', + transform: `translateY(${translate}px)`, + }; +} + +function PivotIndicator() { + const { pivot, activeTraceDirection } = useActivePhaseTraces(); + const { + toolOptions: { selectedTool }, + width, + height, + margin, + yDomain, + xDomain, + mode, + } = useChartData(); + + if (options.phaseCorrectionTwoDimensions.id !== selectedTool || !pivot) { + return null; + } + + let translate = 0; + + if (activeTraceDirection === 'horizontal') { + const scale = get2DXScale({ width, margin, xDomain, mode }); + translate = scale(pivot.value); + } + + if (activeTraceDirection === 'vertical') { + const scale = get2DYScale({ height, margin, yDomain }); + translate = scale(pivot.value); + } + return
; +} + +export default PivotIndicator; diff --git a/src/component/2d/tools/XYLabelPointer.tsx b/src/component/2d/tools/XYLabelPointer.tsx index 51797b0f1..7040be9c5 100644 --- a/src/component/2d/tools/XYLabelPointer.tsx +++ b/src/component/2d/tools/XYLabelPointer.tsx @@ -20,6 +20,7 @@ const style: CSSProperties = { userSelect: 'none', width: '85px', textAlign: 'right', + zIndex: 9, }; function XYLabelPointer({ layout, data1D }) { diff --git a/src/component/2d/utilities/scale.ts b/src/component/2d/utilities/scale.ts index b3ad6ccf9..0a984aa6f 100644 --- a/src/component/2d/utilities/scale.ts +++ b/src/component/2d/utilities/scale.ts @@ -94,15 +94,24 @@ function use1DTraceYScale( return get1DYScale(yDomains[SpectrumId], height, verticalMargin); } +interface SliceYScaleOptions { + margin?: number; + scaleRatio?: number; +} + function getSliceYScale( data: Float64Array, size: number, mode: SpectraDirection, - margin = 10, + options: SliceYScaleOptions = {}, ) { + const { margin = 10, scaleRatio = 1 } = options; const max = xMaxValue(data); size = mode === 'RTL' ? size : size / 2; - return scaleLinear([0, max] as number[], [size - margin, margin]); + return scaleLinear([0, max * scaleRatio] as number[], [ + size - margin, + margin, + ]); } export { diff --git a/src/component/EventsTrackers/KeysListenerTracker.tsx b/src/component/EventsTrackers/KeysListenerTracker.tsx index 4555e92c4..f9c9f05ba 100644 --- a/src/component/EventsTrackers/KeysListenerTracker.tsx +++ b/src/component/EventsTrackers/KeysListenerTracker.tsx @@ -253,6 +253,18 @@ function KeysListenerTracker(props: KeysListenerTrackerProps) { } break; } + case HighlightEventSource.PHASE_CORRECTION_TRACE: { + const { id } = extra || {}; + if (id) { + dispatch({ + type: 'DELETE_PHASE_CORRECTION_TRACE', + payload: { id }, + }); + // remove keys from the highlighted list after delete + remove(); + } + break; + } default: break; diff --git a/src/component/elements/PreferencesButton.tsx b/src/component/elements/PreferencesButton.tsx index a13801b10..5f51f51d6 100644 --- a/src/component/elements/PreferencesButton.tsx +++ b/src/component/elements/PreferencesButton.tsx @@ -1,4 +1,5 @@ import { FaCog } from 'react-icons/fa'; + import ToolTip from './ToolTip/ToolTip'; type PreferencesButtonProps = Pick< diff --git a/src/component/elements/ReactTable/utility/addCustomColumn.tsx b/src/component/elements/ReactTable/utility/addCustomColumn.tsx index 6ecf3c5b3..070b28b40 100644 --- a/src/component/elements/ReactTable/utility/addCustomColumn.tsx +++ b/src/component/elements/ReactTable/utility/addCustomColumn.tsx @@ -1,7 +1,8 @@ import { v4 } from '@lukeed/uuid'; -import { Column } from '../ReactTable'; import { CSSProperties, MouseEvent, ReactNode } from 'react'; +import { Column } from '../ReactTable'; + export type CustomColumn = Column & { index: number }; export type ControlCustomColumn = CustomColumn & { showWhen: string; diff --git a/src/component/header/AutoPeakPickingOptionPanel.tsx b/src/component/header/AutoPeakPickingOptionPanel.tsx index 3b33e4575..d17b900ee 100644 --- a/src/component/header/AutoPeakPickingOptionPanel.tsx +++ b/src/component/header/AutoPeakPickingOptionPanel.tsx @@ -4,7 +4,9 @@ import * as Yup from 'yup'; import { useDispatch } from '../context/DispatchContext'; import Button from '../elements/Button'; +import { InputStyle } from '../elements/Input'; import Label from '../elements/Label'; +import FormikInput from '../elements/formik/FormikInput'; import FormikSelect from '../elements/formik/FormikSelect'; import { useAlert } from '../elements/popup/Alert'; import { @@ -14,8 +16,6 @@ import { import { headerLabelStyle } from './Header'; import { HeaderContainer } from './HeaderContainer'; -import FormikInput from '../elements/formik/FormikInput'; -import { InputStyle } from '../elements/Input'; const inputStyle: InputStyle = { input: { diff --git a/src/component/header/Header.tsx b/src/component/header/Header.tsx index e5434a341..b81768de7 100644 --- a/src/component/header/Header.tsx +++ b/src/component/header/Header.tsx @@ -32,6 +32,7 @@ import AutoPeakPickingOptionPanel from './AutoPeakPickingOptionPanel'; import BaseLineCorrectionPanel from './BaseLineCorrectionPanel'; import { HeaderContainer } from './HeaderContainer'; import PhaseCorrectionPanel from './PhaseCorrectionPanel'; +import PhaseCorrectionTwoDimensionsPanel from './PhaseCorrectionTwoDimensionsPanel'; import RangesPickingOptionPanel from './RangesPickingOptionPanel'; import ZeroFillingOptionsPanel from './ZeroFillingOptionsPanel'; import Zones2DOptionPanel from './Zones2DOptionPanel'; @@ -112,6 +113,8 @@ function HeaderInner(props: HeaderInnerProps) { return ; case options.phaseCorrection.id: return ; + case options.phaseCorrectionTwoDimensions.id: + return ; case options.peakPicking.id: return ; case options.rangePicking.id: @@ -121,6 +124,7 @@ function HeaderInner(props: HeaderInnerProps) { case options.zonePicking.id: return ; default: + return null; break; } }, [selectedOptionPanel]); diff --git a/src/component/header/PhaseCorrectionTwoDimensionsPanel.tsx b/src/component/header/PhaseCorrectionTwoDimensionsPanel.tsx new file mode 100644 index 000000000..b1d8a219e --- /dev/null +++ b/src/component/header/PhaseCorrectionTwoDimensionsPanel.tsx @@ -0,0 +1,190 @@ +import { Spectrum1D } from 'nmr-load-save'; +import { + CSSProperties, + useCallback, + useDeferredValue, + useEffect, + useRef, + useState, +} from 'react'; + +import { stringCapitalize } from '../../utils/stringCapitalize'; +import { useActivePhaseTraces } from '../2d/1d-tracer/phase-correction-traces/useActivePhaseTraces'; +import { useDispatch } from '../context/DispatchContext'; +import ActionButtons from '../elements/ActionButtons'; +import Input, { InputStyle } from '../elements/Input'; +import InputRange from '../elements/InputRange'; +import Label from '../elements/Label'; +import Select from '../elements/Select'; +import useSpectrum from '../hooks/useSpectrum'; +import { TraceDirection } from '../reducer/Reducer'; + +import { headerLabelStyle } from './Header'; +import { HeaderContainer } from './HeaderContainer'; + +const selectStyle: CSSProperties = { + marginLeft: '5px', + marginRight: '10px', + border: 'none', + height: '20px', +}; + +const inputStyle: InputStyle = { + input: { + width: '70px', + textAlign: 'center', + }, + inputWrapper: { + height: '100%', + }, +}; + +const TRACE_DIRECTIONS: Array<{ label: string; value: TraceDirection }> = ( + ['horizontal', 'vertical'] as TraceDirection[] +).map((key) => ({ + label: stringCapitalize(key), + value: key, +})); + +const emptyData = { datum: {}, filter: null }; + +export default function PhaseCorrectionTwoDimensionsPanel() { + const { ph0, ph1, pivot, activeTraceDirection } = useActivePhaseTraces(); + + const { data } = useSpectrum(emptyData) as Spectrum1D; + const activeDirection = useDeferredValue(activeTraceDirection); + + const dispatch = useDispatch(); + const [value, setValue] = useState({ ph0: 0, ph1: 0 }); + const valueRef = useRef({ ph0: 0, ph1: 0 }); + + const ph0Ref = useRef(); + const ph1Ref = useRef(); + + useEffect(() => { + if (activeDirection !== activeTraceDirection) { + setValue({ ph0, ph1 }); + valueRef.current = { ph0, ph1 }; + } + }, [activeDirection, activeTraceDirection, ph0, ph1]); + + const calcPhaseCorrectionHandler = useCallback( + (newValues, filedName) => { + if (filedName === 'ph1' && data.re && pivot) { + const diff0 = newValues.ph0 - valueRef.current.ph0; + const diff1 = newValues.ph1 - valueRef.current.ph1; + newValues.ph0 += + diff0 - (diff1 * (data.re.length - pivot?.index)) / data.re.length; + } + dispatch({ + type: 'CALCULATE_TOW_DIMENSIONS_MANUAL_PHASE_CORRECTION_FILTER', + payload: newValues, + }); + }, + [data.re, dispatch, pivot], + ); + + const updateInputRangeInitialValue = useCallback((value) => { + // update InputRange initial value + ph0Ref.current.setValue(value.ph0); + ph1Ref.current.setValue(value.ph1); + }, []); + + const handleInput = useCallback( + (e) => { + const { name, value } = e.target; + if (e.target) { + const newValue = { ...valueRef.current, [name]: Number(value) }; + + if (String(value).trim() !== '-') { + calcPhaseCorrectionHandler(newValue, name); + } + updateInputRangeInitialValue(newValue); + valueRef.current = newValue; + setValue(valueRef.current); + } + }, + [calcPhaseCorrectionHandler, updateInputRangeInitialValue], + ); + + const handleRangeChange = useCallback( + (e) => { + const newValue = { ...valueRef.current, [e.name]: e.value }; + calcPhaseCorrectionHandler(newValue, e.name); + updateInputRangeInitialValue(newValue); + valueRef.current = newValue; + setValue(valueRef.current); + }, + [calcPhaseCorrectionHandler, updateInputRangeInitialValue], + ); + + const handleCancelFilter = useCallback(() => { + dispatch({ + type: 'RESET_SELECTED_TOOL', + }); + }, [dispatch]); + + function onChangeHandler(direction) { + dispatch({ + type: 'CHANGE_PHASE_CORRECTION_DIRECTION', + payload: { direction }, + }); + } + + /*eslint-disable unicorn/consistent-function-scoping */ + function handleApplyFilter() { + //TODO implement apply filter + } + + return ( + + + + + + + + + + + ); +} diff --git a/src/component/header/RangesPickingOptionPanel.tsx b/src/component/header/RangesPickingOptionPanel.tsx index d94dc98fe..cd154f304 100644 --- a/src/component/header/RangesPickingOptionPanel.tsx +++ b/src/component/header/RangesPickingOptionPanel.tsx @@ -5,6 +5,7 @@ import { useDispatch } from '../context/DispatchContext'; import Button from '../elements/Button'; import Label from '../elements/Label'; import FormikCheckBox from '../elements/formik/FormikCheckBox'; +import FormikInput from '../elements/formik/FormikInput'; import { useAlert } from '../elements/popup/Alert'; import { MIN_AREA_POINTS, @@ -13,7 +14,6 @@ import { import { headerLabelStyle } from './Header'; import { HeaderContainer } from './HeaderContainer'; -import FormikInput from '../elements/formik/FormikInput'; const validationSchema = Yup.object().shape({ minMaxRatio: Yup.number().min(0).required(), diff --git a/src/component/header/Zones2DOptionPanel.tsx b/src/component/header/Zones2DOptionPanel.tsx index ffd4a650d..703f63c5c 100644 --- a/src/component/header/Zones2DOptionPanel.tsx +++ b/src/component/header/Zones2DOptionPanel.tsx @@ -5,11 +5,11 @@ import * as Yup from 'yup'; import { useDispatch } from '../context/DispatchContext'; import Button from '../elements/Button'; import Label from '../elements/Label'; +import FormikInput from '../elements/formik/FormikInput'; import FormikOnChange from '../elements/formik/FormikOnChange'; import { headerLabelStyle } from './Header'; import { HeaderContainer } from './HeaderContainer'; -import FormikInput from '../elements/formik/FormikInput'; const validationSchema = Yup.object().shape({ zonesNoiseFactor: Yup.number().min(0).required(), diff --git a/src/component/highlight/index.tsx b/src/component/highlight/index.tsx index 58da5a32a..d8385e65c 100644 --- a/src/component/highlight/index.tsx +++ b/src/component/highlight/index.tsx @@ -25,6 +25,7 @@ export enum HighlightEventSource { MULTIPLE_ANALYSIS_ZONE = 'MULTIPLE_ANALYSIS_ZONE', DATABASE = 'DATABASE', ATOM = 'ATOM', + PHASE_CORRECTION_TRACE = 'PHASE_CORRECTION_TRACE', UNKNOWN = 'UNKNOWN', } diff --git a/src/component/hooks/useActiveSpectrumIntegralsViewState.ts b/src/component/hooks/useActiveSpectrumIntegralsViewState.ts new file mode 100644 index 000000000..b1e427df7 --- /dev/null +++ b/src/component/hooks/useActiveSpectrumIntegralsViewState.ts @@ -0,0 +1,22 @@ +import { IntegralsViewState } from 'nmr-load-save'; + +import { useChartData } from '../context/ChartContext'; + +import { useActiveSpectrum } from './useActiveSpectrum'; + +export const defaultIntegralsViewState: IntegralsViewState = { + scaleRatio: 1, +}; + +export function useActiveSpectrumIntegralsViewState() { + const activeSpectrum = useActiveSpectrum(); + const { + view: { integrals }, + } = useChartData(); + + if (activeSpectrum?.id && integrals[activeSpectrum?.id]) { + return integrals[activeSpectrum?.id]; + } else { + return defaultIntegralsViewState; + } +} diff --git a/src/component/hooks/useActiveSpectrumRangesViewState.ts b/src/component/hooks/useActiveSpectrumRangesViewState.ts index 6ac23eefe..551f860eb 100644 --- a/src/component/hooks/useActiveSpectrumRangesViewState.ts +++ b/src/component/hooks/useActiveSpectrumRangesViewState.ts @@ -7,9 +7,10 @@ import { useActiveSpectrum } from './useActiveSpectrum'; export const defaultRangesViewState: RangesViewState = { showPeaks: false, showMultiplicityTrees: false, - showRangesIntegrals: false, + showIntegrals: false, showJGraph: false, displayingMode: 'spread', + integralsScaleRatio: 1, }; export function useActiveSpectrumRangesViewState() { diff --git a/src/component/hooks/useCheckToolsVisibility.ts b/src/component/hooks/useCheckToolsVisibility.ts index ceccb7809..b3a45ba5f 100644 --- a/src/component/hooks/useCheckToolsVisibility.ts +++ b/src/component/hooks/useCheckToolsVisibility.ts @@ -58,7 +58,7 @@ export function useCheckToolsVisibility(): ( modeFlag && spectrumCheckFlag && (!extraInfoCheckParameters || - checkInfo(extraInfoCheckParameters, spectrum?.info)) + checkInfo(extraInfoCheckParameters, spectrum?.info as SpectrumInfo)) ); }, diff --git a/src/component/hooks/useIntegralPath.ts b/src/component/hooks/useIntegralPath.ts index 58a772146..90fba1e09 100644 --- a/src/component/hooks/useIntegralPath.ts +++ b/src/component/hooks/useIntegralPath.ts @@ -1,78 +1,51 @@ -import { NmrData1D } from 'cheminfo-types'; import { ScaleLinear } from 'd3'; -import { xyIntegral, xyReduce } from 'ml-spectra-processing'; -import { useMemo } from 'react'; +import { xyReduce } from 'ml-spectra-processing'; import { getIntegralYScale } from '../1d/utilities/scale'; import { useChartData } from '../context/ChartContext'; import { PathBuilder } from '../utility/PathBuilder'; -import { useActiveSpectrum } from './useActiveSpectrum'; -import { useVerticalAlign } from './useVerticalAlign'; import { useXScale } from './useXScale'; -function useIntegralYDomain(): ScaleLinear { - const { height, margin, integralsYDomains } = useChartData(); - const verticalAlign = useVerticalAlign(); - const activeSpectrum = useActiveSpectrum(); - return useMemo( - () => - getIntegralYScale({ - height, - margin, - verticalAlign, - activeSpectrum, - integralsYDomains, - }), - [activeSpectrum, height, integralsYDomains, margin, verticalAlign], - ); +function useIntegralYDomain( + max: number, + scaleRatio = 1, +): ScaleLinear { + const { height, margin } = useChartData(); + return getIntegralYScale({ + height, + margin, + yDomain: [0, max], + scaleRatio, + }); } -export default function useIntegralPath(integralOptions: { - from: number; - to: number; -}) { - const { data } = useChartData(); - - const activeSpectrum = useActiveSpectrum(); - const scaleX = useXScale(); - const scaleY = useIntegralYDomain(); - const integral = useMemo(() => { - if (activeSpectrum) { - const { x, re } = data[activeSpectrum?.index].data as NmrData1D; - const { from, to } = integralOptions; - return xyIntegral( - { x, y: re }, - { - from, - to, - reverse: true, - }, - ); - } - return { x: [], y: [] }; - }, [activeSpectrum, data, integralOptions]); +interface UseIntegralPathOptions { + x: Float64Array; + y: Float64Array; + max: number; + scaleRatio: number; +} - const paths = useMemo(() => { - if (integral) { - const xySeries = xyReduce(integral, { - // from: xDomain[0], - // to: xDomain[1], - nbPoints: 200, - optimize: true, - }); +export default function useIntegralPath(options: UseIntegralPathOptions) { + const { x, y, max, scaleRatio } = options; - const pathBuilder = new PathBuilder(); - pathBuilder.moveTo(scaleX(xySeries.x[0]), scaleY(xySeries.y[0])); - for (let i = 1; i < xySeries.x.length; i++) { - pathBuilder.lineTo(scaleX(xySeries.x[i]), scaleY(xySeries.y[i])); - } + const scaleX = useXScale(); + const scaleY = useIntegralYDomain(max, scaleRatio); + + const xySeries = xyReduce( + { x, y }, + { + nbPoints: 200, + optimize: true, + }, + ); - return pathBuilder.toString(); - } else { - return ''; - } - }, [integral, scaleX, scaleY]); + const pathBuilder = new PathBuilder(); + pathBuilder.moveTo(scaleX(xySeries.x[0]), scaleY(xySeries.y[0])); + for (let i = 1; i < xySeries.x.length; i++) { + pathBuilder.lineTo(scaleX(xySeries.x[i]), scaleY(xySeries.y[i])); + } - return paths; + return pathBuilder.toString(); } diff --git a/src/component/modal/AlignSpectraModal.tsx b/src/component/modal/AlignSpectraModal.tsx index e67464e12..263f565d9 100644 --- a/src/component/modal/AlignSpectraModal.tsx +++ b/src/component/modal/AlignSpectraModal.tsx @@ -1,24 +1,24 @@ /** @jsxImportSource @emotion/react */ import { Formik } from 'formik'; +import { xFindClosestIndex } from 'ml-spectra-processing'; +import { Spectrum1D } from 'nmr-load-save'; import { useEffect, useState } from 'react'; +import * as Yup from 'yup'; import { REFERENCES } from '../../data/constants/References'; +import { CalibrateOptions } from '../../data/data1d/Spectrum1D/getReferenceShift'; import { useDispatch } from '../context/DispatchContext'; import Button from '../elements/Button'; import CloseButton from '../elements/CloseButton'; import { InputStyle } from '../elements/Input'; import Label, { LabelStyle } from '../elements/Label'; +import Message from '../elements/Message'; import Select from '../elements/Select'; import FormikInput from '../elements/formik/FormikInput'; +import useSpectraByActiveNucleus from '../hooks/useSpectraPerNucleus'; import Events from '../utility/Events'; import { ModalStyles } from './ModalStyle'; -import { CalibrateOptions } from '../../data/data1d/Spectrum1D/getReferenceShift'; -import { Spectrum1D } from 'nmr-load-save'; -import { xFindClosestIndex } from 'ml-spectra-processing'; -import useSpectraByActiveNucleus from '../hooks/useSpectraPerNucleus'; -import * as Yup from 'yup'; -import Message from '../elements/Message'; const labelStyle: LabelStyle = { label: { flex: 4, fontWeight: '500' }, diff --git a/src/component/panels/IntegralsPanel/IntegralTable.tsx b/src/component/panels/IntegralsPanel/IntegralTable.tsx index adc2d2782..28dbf18a3 100644 --- a/src/component/panels/IntegralsPanel/IntegralTable.tsx +++ b/src/component/panels/IntegralsPanel/IntegralTable.tsx @@ -15,10 +15,10 @@ import addCustomColumn, { import Select from '../../elements/Select'; import { usePanelPreferences } from '../../hooks/usePanelPreferences'; import { formatNumber } from '../../utility/formatNumber'; +import NoDataForFid from '../extra/placeholder/NoDataForFid'; import NoTableData from '../extra/placeholder/NoTableData'; import { IntegralPanelInnerProps } from './IntegralPanel'; -import NoDataForFid from '../extra/placeholder/NoDataForFid'; const selectStyle = { width: '100%', border: 'none' }; diff --git a/src/component/panels/IntegralsPanel/IntegralsPreferences.tsx b/src/component/panels/IntegralsPanel/IntegralsPreferences.tsx index 71dd28484..ed2beae5b 100644 --- a/src/component/panels/IntegralsPanel/IntegralsPreferences.tsx +++ b/src/component/panels/IntegralsPanel/IntegralsPreferences.tsx @@ -12,6 +12,7 @@ import { usePreferences } from '../../context/PreferencesContext'; import Label from '../../elements/Label'; import FormikColorInput from '../../elements/formik/FormikColorInput'; import { formatFieldLabelStyle } from '../../elements/formik/FormikColumnFormatField'; +import FormikInput from '../../elements/formik/FormikInput'; import useNucleus from '../../hooks/useNucleus'; import { usePanelPreferencesByNuclei } from '../../hooks/usePanelPreferences'; import { getUniqueNuclei } from '../../utility/getUniqueNuclei'; @@ -20,7 +21,6 @@ import { NucleusPreferences, } from '../extra/preferences/NucleusPreferences'; import { PreferencesContainer } from '../extra/preferences/PreferencesContainer'; -import FormikInput from '../../elements/formik/FormikInput'; const formatFields: NucleusPreferenceField[] = [ { diff --git a/src/component/panels/MoleculesPanel/useAtomAssignment.tsx b/src/component/panels/MoleculesPanel/useAtomAssignment.tsx index 8e858be4a..6b1ee9157 100644 --- a/src/component/panels/MoleculesPanel/useAtomAssignment.tsx +++ b/src/component/panels/MoleculesPanel/useAtomAssignment.tsx @@ -12,6 +12,7 @@ import { filterForIDsWithAssignment } from '../../assignment/utilities/filterFor import { useDispatch } from '../../context/DispatchContext'; import { useAlert } from '../../elements/popup/Alert'; import { HighlightEventSource, useHighlightData } from '../../highlight'; +import { DisplayerMode } from '../../reducer/Reducer'; import { AtomData, @@ -21,7 +22,6 @@ import { getHighlightsOnHover, toggleDiaIDs, } from './Utilities'; -import { DisplayerMode } from '../../reducer/Reducer'; interface UseAtomAssignmentProps { displayerMode: DisplayerMode; diff --git a/src/component/panels/Panels.tsx b/src/component/panels/Panels.tsx index aed5caa42..3aa0708f3 100644 --- a/src/component/panels/Panels.tsx +++ b/src/component/panels/Panels.tsx @@ -6,6 +6,7 @@ import { Accordion } from 'react-science/ui'; import { useChartData } from '../context/ChartContext'; import { usePreferences } from '../context/PreferencesContext'; import useCheckExperimentalFeature from '../hooks/useCheckExperimentalFeature'; +import { DisplayerMode } from '../reducer/Reducer'; import AutomaticAssignment from './AutomaticAssignment/AutomaticAssignment'; import InformationPanel from './InformationPanel'; @@ -22,7 +23,6 @@ import DatabasePanel from './databasePanel/DatabasePanel'; import FilterPanel from './filtersPanel/FilterPanel'; import PredictionPane from './predictionPanel/PredictionPanel'; import SpectrumSimulation from './spectrumSimulation/SpectrumSimulation'; -import { DisplayerMode } from '../reducer/Reducer'; interface AccordionItem { title: string; diff --git a/src/component/panels/PeaksPanel/PeaksTable.tsx b/src/component/panels/PeaksPanel/PeaksTable.tsx index 1c4670733..8ffab2038 100644 --- a/src/component/panels/PeaksPanel/PeaksTable.tsx +++ b/src/component/panels/PeaksPanel/PeaksTable.tsx @@ -1,4 +1,5 @@ import lodashGet from 'lodash/get'; +import { Info1D } from 'nmr-processing'; import { useCallback, useMemo, memo } from 'react'; import { FaEdit, FaRegTrashAlt } from 'react-icons/fa'; @@ -14,11 +15,10 @@ import { positions, transitions } from '../../elements/popup/options'; import { usePanelPreferences } from '../../hooks/usePanelPreferences'; import EditPeakShapeModal from '../../modal/EditPeakShapeModal'; import { formatNumber } from '../../utility/formatNumber'; +import NoDataForFid from '../extra/placeholder/NoDataForFid'; import NoTableData from '../extra/placeholder/NoTableData'; import { PeakRecord } from './PeaksPanel'; -import { Info1D } from 'nmr-processing'; -import NoDataForFid from '../extra/placeholder/NoDataForFid'; interface PeaksTableProps { activeTab: string; diff --git a/src/component/panels/PeaksPanel/PeaksToggleActions.tsx b/src/component/panels/PeaksPanel/PeaksToggleActions.tsx index d0c2c5892..8216f6f9c 100644 --- a/src/component/panels/PeaksPanel/PeaksToggleActions.tsx +++ b/src/component/panels/PeaksPanel/PeaksToggleActions.tsx @@ -1,7 +1,8 @@ import { SvgNmrPeaks, SvgNmrPeaksTopLabels } from 'cheminfo-font'; -import ActiveButton, { ActiveButtonProps } from '../../elements/ActiveButton'; import { CSSProperties } from 'react'; +import ActiveButton, { ActiveButtonProps } from '../../elements/ActiveButton'; + interface PeaksToggleProps { disbale: boolean; displayingMode: 'single' | 'spread'; diff --git a/src/component/panels/RangesPanel/RangesHeader.tsx b/src/component/panels/RangesPanel/RangesHeader.tsx index b01d1cc63..c995c946b 100644 --- a/src/component/panels/RangesPanel/RangesHeader.tsx +++ b/src/component/panels/RangesPanel/RangesHeader.tsx @@ -65,7 +65,7 @@ function RangesHeader({ const { showMultiplicityTrees, showJGraph, - showRangesIntegrals, + showIntegrals, showPeaks, displayingMode, } = useActiveSpectrumRangesViewState(); @@ -114,7 +114,7 @@ function RangesHeader({ function handleShowIntegrals() { dispatch({ type: 'TOGGLE_RANGES_VIEW_PROPERTY', - payload: { key: 'showRangesIntegrals' }, + payload: { key: 'showIntegrals' }, }); } @@ -248,10 +248,10 @@ function RangesHeader({ { + function onSaveHandler() { onSave?.(tolerance); onClose?.(); - }, [onClose, onSave, tolerance]); - - const onChangeHandler = useCallback( - (e, atomType: string) => { - const value: string = e.target.value; - if (value.trim().length > 0) { - setTolerance({ ...tolerance, [atomType]: Number(value) }); - setIsValid({ ...isValid, [atomType]: true }); - } else { - setIsValid({ ...isValid, [atomType]: false }); - } - }, - [isValid, tolerance], - ); + } - const rows = useMemo(() => { - return tolerance - ? Object.keys(tolerance).map((atomType) => { - return ( - - {atomType} - - onChangeHandler(e, atomType)} - defaultValue={tolerance[atomType]} - style={ - !isValid[atomType] ? { backgroundColor: 'orange' } : {} - } - /> - - - ); - }) - : undefined; - }, [isValid, onChangeHandler, tolerance]); + function onChangeHandler(e, atomType: string) { + const value: string = e.target.value; + if (value.trim().length > 0) { + setTolerance({ ...tolerance, [atomType]: Number(value) }); + setIsValid({ ...isValid, [atomType]: true }); + } else { + setIsValid({ ...isValid, [atomType]: false }); + } + } return (
@@ -153,7 +128,13 @@ export default function SetShiftToleranceModal({ Value - {rows} + + +