From b7738bff2f43155ec0e54451cc2bd5c8d8d9801f Mon Sep 17 00:00:00 2001 From: Starla Huang Date: Sat, 23 Dec 2023 16:54:08 +0800 Subject: [PATCH] #3666 make opening structure in center of the screen --- .../editor/shared/coordinates.test.ts | 2 +- .../src/application/editor/Editor.ts | 2 +- .../src/application/editor/index.ts | 1 + .../application/editor/shared/coordinates.ts | 4 +- .../src/application/editor/tools/Bond.ts | 2 +- .../src/application/editor/tools/Monomer.ts | 2 +- .../src/application/editor/tools/Paste.ts | 82 +++++++++++++++++++ .../src/application/editor/tools/RnaPreset.ts | 2 +- .../editor/tools/SelectRectangle.ts | 2 +- .../render/renderers/BaseMonomerRenderer.ts | 2 +- .../src/domain/entities/DrawingEntity.ts | 2 +- .../helpers/attachmentPointCalculations.ts | 2 +- .../ket/fromKet/monomerToDrawingEntity.ts | 8 +- .../domain/serializers/ket/ketSerializer.ts | 35 +++++++- .../src/components/modal/Open/Open.tsx | 10 ++- 15 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 packages/ketcher-core/src/application/editor/tools/Paste.ts diff --git a/packages/ketcher-core/__tests__/application/editor/shared/coordinates.test.ts b/packages/ketcher-core/__tests__/application/editor/shared/coordinates.test.ts index 33a1b1927b..8dd9eb1969 100644 --- a/packages/ketcher-core/__tests__/application/editor/shared/coordinates.test.ts +++ b/packages/ketcher-core/__tests__/application/editor/shared/coordinates.test.ts @@ -1,4 +1,4 @@ -import Coordinates from 'application/editor/shared/coordinates'; +import { Coordinates } from 'application/editor/shared/coordinates'; import ZoomTool from 'application/editor/tools/Zoom'; import { ZoomTransform } from 'd3'; import { Vec2 } from 'domain/entities'; diff --git a/packages/ketcher-core/src/application/editor/Editor.ts b/packages/ketcher-core/src/application/editor/Editor.ts index d0795fcad0..5672a8cf79 100644 --- a/packages/ketcher-core/src/application/editor/Editor.ts +++ b/packages/ketcher-core/src/application/editor/Editor.ts @@ -14,7 +14,7 @@ import { MonomerItemType } from 'domain/types'; import { RenderersManager } from 'application/render/renderers/RenderersManager'; import { DrawingEntitiesManager } from 'domain/entities/DrawingEntitiesManager'; import ZoomTool from './tools/Zoom'; -import Coordinates from './shared/coordinates'; +import { Coordinates } from './shared/coordinates'; import { editorEvents, renderersEvents, diff --git a/packages/ketcher-core/src/application/editor/index.ts b/packages/ketcher-core/src/application/editor/index.ts index 48f5baaa36..ae03ffaf47 100644 --- a/packages/ketcher-core/src/application/editor/index.ts +++ b/packages/ketcher-core/src/application/editor/index.ts @@ -26,6 +26,7 @@ export const vectorUtils = { export * from './operations'; export * from './actions'; export * from './shared/constants'; +export * from './shared/coordinates'; export * from './editor.types'; export * from './Editor'; export * from './EditorHistory'; diff --git a/packages/ketcher-core/src/application/editor/shared/coordinates.ts b/packages/ketcher-core/src/application/editor/shared/coordinates.ts index aa554b5804..03013d312d 100644 --- a/packages/ketcher-core/src/application/editor/shared/coordinates.ts +++ b/packages/ketcher-core/src/application/editor/shared/coordinates.ts @@ -6,7 +6,7 @@ import ZoomTool from '../tools/Zoom'; * `canvas` -- The real coordinates used to draw entities * `view` -- The zoomed canvas coordinates */ -class Coordinates { +export class Coordinates { static canvasToModel(position: Vec2) { const settings = provideEditorSettings(); return position.scaled(1 / settings.scale); @@ -38,5 +38,3 @@ class Coordinates { return ZoomTool.instance.invertZoom(position); } } - -export default Coordinates; diff --git a/packages/ketcher-core/src/application/editor/tools/Bond.ts b/packages/ketcher-core/src/application/editor/tools/Bond.ts index 4f68009e90..5f60c99dc6 100644 --- a/packages/ketcher-core/src/application/editor/tools/Bond.ts +++ b/packages/ketcher-core/src/application/editor/tools/Bond.ts @@ -24,7 +24,7 @@ import { Peptide } from 'domain/entities/Peptide'; import { Sugar } from 'domain/entities/Sugar'; import { RNABase } from 'domain/entities/RNABase'; import { Phosphate } from 'domain/entities/Phosphate'; -import Coordinates from 'application/editor/shared/coordinates'; +import { Coordinates } from '../shared/coordinates'; class PolymerBond implements BaseTool { private bondRenderer?: PolymerBondRenderer; diff --git a/packages/ketcher-core/src/application/editor/tools/Monomer.ts b/packages/ketcher-core/src/application/editor/tools/Monomer.ts index dbab6a8eba..db2a0005af 100644 --- a/packages/ketcher-core/src/application/editor/tools/Monomer.ts +++ b/packages/ketcher-core/src/application/editor/tools/Monomer.ts @@ -25,7 +25,7 @@ import { BaseMonomerRenderer } from 'application/render/renderers'; import { MonomerItemType } from 'domain/types'; import { monomerFactory } from '../operations/monomer/monomerFactory'; import assert from 'assert'; -import Coordinates from '../shared/coordinates'; +import { Coordinates } from '../shared/coordinates'; class MonomerTool implements BaseTool { private monomerPreview: diff --git a/packages/ketcher-core/src/application/editor/tools/Paste.ts b/packages/ketcher-core/src/application/editor/tools/Paste.ts new file mode 100644 index 0000000000..5f41196dd5 --- /dev/null +++ b/packages/ketcher-core/src/application/editor/tools/Paste.ts @@ -0,0 +1,82 @@ +// /**************************************************************************** +// * Copyright 2021 EPAM Systems +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// ***************************************************************************/ +// import { Coordinates, CoreEditor, EditorHistory } from 'application/editor'; +// import { BaseTool } from 'application/editor/tools/Tool'; +// import { SupportedFormat, identifyStructFormat } from 'application/formatters'; +// import assert from 'assert'; +// import { IndigoProvider } from 'ketcher-react'; +// import { KetSerializer } from 'domain/serializers'; +// import { ChemicalMimeType, StructService } from 'domain/services'; +// import { Vec2 } from 'domain/entities'; + +// class PasteTool implements BaseTool { +// private history: EditorHistory; +// private readonly struct: string; + +// constructor(private editor: CoreEditor, struct: string) { +// this.editor = editor; +// this.struct = struct; +// this.history = new EditorHistory(editor); +// this.convertStruct(); +// } + +// async convertStruct() { +// const isKet = identifyStructFormat(this.struct) === SupportedFormat.ket; +// const ketSerializer = new KetSerializer(); +// const editor = CoreEditor.provideEditorInstance(); +// if (isKet) { +// this.addToCanvas({ struct: this.struct, ketSerializer, editor }); +// return; +// } +// const indigo = IndigoProvider.getIndigo() as StructService; +// const ketStruct = await indigo.convert({ +// struct: this.struct, +// output_format: ChemicalMimeType.KET, +// }); +// this.addToCanvas({ struct: ketStruct.struct, ketSerializer, editor }); +// } + +// addToCanvas({ +// ketSerializer, +// editor, +// struct, +// }: { +// ketSerializer: KetSerializer; +// editor: CoreEditor; +// struct: string; +// }) { +// const centerPointOfCanvas = Coordinates.canvasToModel( +// new Vec2( +// this.editor.canvasOffset.width / 2, +// this.editor.canvasOffset.height / 2, +// ), +// ); +// const deserialisedKet = ketSerializer.deserializeToDrawingEntities( +// struct, +// centerPointOfCanvas, +// ); +// assert(deserialisedKet); +// deserialisedKet.drawingEntitiesManager.mergeInto( +// editor.drawingEntitiesManager, +// ); +// this.history.update(deserialisedKet.modelChanges); +// editor.renderersContainer.update(deserialisedKet.modelChanges); +// } + +// destroy() {} +// } + +// export { PasteTool }; diff --git a/packages/ketcher-core/src/application/editor/tools/RnaPreset.ts b/packages/ketcher-core/src/application/editor/tools/RnaPreset.ts index 40e9739fc1..4d85cb41a0 100644 --- a/packages/ketcher-core/src/application/editor/tools/RnaPreset.ts +++ b/packages/ketcher-core/src/application/editor/tools/RnaPreset.ts @@ -23,7 +23,7 @@ import { MonomerItemType } from 'domain/types'; import { monomerFactory } from '../operations/monomer/monomerFactory'; import { RNABase } from 'domain/entities/RNABase'; import { Phosphate } from 'domain/entities/Phosphate'; -import Coordinates from 'application/editor/shared/coordinates'; +import { Coordinates } from '../shared/coordinates'; class RnaPresetTool implements Tool { rnaBase: MonomerItemType | undefined; diff --git a/packages/ketcher-core/src/application/editor/tools/SelectRectangle.ts b/packages/ketcher-core/src/application/editor/tools/SelectRectangle.ts index 0d2b9620c9..c4134726ea 100644 --- a/packages/ketcher-core/src/application/editor/tools/SelectRectangle.ts +++ b/packages/ketcher-core/src/application/editor/tools/SelectRectangle.ts @@ -19,7 +19,7 @@ import { brush as d3Brush, select } from 'd3'; import { BaseRenderer } from 'application/render/renderers/BaseRenderer'; import { Command } from 'domain/entities/Command'; import { BaseTool } from 'application/editor/tools/Tool'; -import Coordinates from '../shared/coordinates'; +import { Coordinates } from '../shared/coordinates'; class SelectRectangle implements BaseTool { private brush; diff --git a/packages/ketcher-core/src/application/render/renderers/BaseMonomerRenderer.ts b/packages/ketcher-core/src/application/render/renderers/BaseMonomerRenderer.ts index 15d934a91a..0ea14137a0 100644 --- a/packages/ketcher-core/src/application/render/renderers/BaseMonomerRenderer.ts +++ b/packages/ketcher-core/src/application/render/renderers/BaseMonomerRenderer.ts @@ -11,12 +11,12 @@ import { checkFor0and360, } from 'domain/helpers/attachmentPointCalculations'; import { AttachmentPoint } from 'domain/AttachmentPoint'; -import Coordinates from 'application/editor/shared/coordinates'; import { Vec2 } from 'domain/entities'; import { AttachmentPointConstructorParams, AttachmentPointName, } from 'domain/types'; +import { Coordinates } from 'application/editor/shared/coordinates'; export abstract class BaseMonomerRenderer extends BaseRenderer { private editorEvents: typeof editorEvents; diff --git a/packages/ketcher-core/src/domain/entities/DrawingEntity.ts b/packages/ketcher-core/src/domain/entities/DrawingEntity.ts index b4d8f01ad1..d633b072b7 100644 --- a/packages/ketcher-core/src/domain/entities/DrawingEntity.ts +++ b/packages/ketcher-core/src/domain/entities/DrawingEntity.ts @@ -1,7 +1,7 @@ import { Vec2 } from 'domain/entities/vec2'; import { BaseRenderer } from 'application/render/renderers/BaseRenderer'; import assert from 'assert'; -import Coordinates from 'application/editor/shared/coordinates'; +import { Coordinates } from 'application/editor/shared/coordinates'; let id = 0; export abstract class DrawingEntity { diff --git a/packages/ketcher-core/src/domain/helpers/attachmentPointCalculations.ts b/packages/ketcher-core/src/domain/helpers/attachmentPointCalculations.ts index 95c54820c2..dbcacbea92 100644 --- a/packages/ketcher-core/src/domain/helpers/attachmentPointCalculations.ts +++ b/packages/ketcher-core/src/domain/helpers/attachmentPointCalculations.ts @@ -1,4 +1,4 @@ -import CoordinatesTool from 'application/editor/shared/coordinates'; +import { Coordinates as CoordinatesTool } from 'application/editor/shared/coordinates'; import { BaseMonomer } from 'domain/entities'; import { Vec2 } from 'domain/entities/vec2'; diff --git a/packages/ketcher-core/src/domain/serializers/ket/fromKet/monomerToDrawingEntity.ts b/packages/ketcher-core/src/domain/serializers/ket/fromKet/monomerToDrawingEntity.ts index 1b7810fa80..329adf4472 100644 --- a/packages/ketcher-core/src/domain/serializers/ket/fromKet/monomerToDrawingEntity.ts +++ b/packages/ketcher-core/src/domain/serializers/ket/fromKet/monomerToDrawingEntity.ts @@ -4,17 +4,17 @@ import { } from 'application/formatters/types/ket'; import { Struct, Vec2 } from 'domain/entities'; import { DrawingEntitiesManager } from 'domain/entities/DrawingEntitiesManager'; -import { switchIntoChemistryCoordSystem } from 'domain/serializers/ket/helpers'; export function monomerToDrawingEntity( node: IKetMonomerNode, template: IKetMonomerTemplate, struct: Struct, drawingEntitiesManager: DrawingEntitiesManager, + offset?: Vec2, ) { - const position: Vec2 = switchIntoChemistryCoordSystem( - new Vec2(node.position.x, node.position.y), - ); + const position: Vec2 = offset + ? new Vec2(node.position).add(offset) + : new Vec2(node.position); return drawingEntitiesManager.addMonomer( { struct, diff --git a/packages/ketcher-core/src/domain/serializers/ket/ketSerializer.ts b/packages/ketcher-core/src/domain/serializers/ket/ketSerializer.ts index c122be94a3..62fa7fc7bf 100644 --- a/packages/ketcher-core/src/domain/serializers/ket/ketSerializer.ts +++ b/packages/ketcher-core/src/domain/serializers/ket/ketSerializer.ts @@ -215,6 +215,11 @@ export class KetSerializer implements Serializer { return { error: true }; } let error = false; + let xmin = 1e50; + let ymin = xmin; + let xmax = -xmin; + let ymax = -ymin; + parsedFileContent.root.nodes.forEach((node) => { const nodeDefinition = parsedFileContent[node.$ref]; @@ -224,6 +229,13 @@ export class KetSerializer implements Serializer { parsedFileContent, editor, ); + nodeDefinition.position = switchIntoChemistryCoordSystem( + new Vec2(nodeDefinition.position.x, nodeDefinition.position.y), + ); + xmin = Math.min(xmin, nodeDefinition.position.x); + ymin = Math.min(ymin, nodeDefinition.position.y); + xmax = Math.max(xmax, nodeDefinition.position.x); + ymax = Math.max(ymax, nodeDefinition.position.y); } }); if (error) { @@ -234,7 +246,11 @@ export class KetSerializer implements Serializer { this.validateConnectionTypeAndEndpoints(connection, editor); }, ); - return { error, parsedFileContent }; + return { + error, + parsedFileContent, + structCenter: new Vec2((xmin + xmax) / 2, (ymin + ymax) / 2), + }; } deserializeToStruct(fileContent: string) { @@ -284,10 +300,20 @@ export class KetSerializer implements Serializer { return fileContentForMicromolecules; } - deserializeToDrawingEntities(fileContent: string) { - const { error: hasValidationErrors, parsedFileContent } = - this.parseAndValidateMacromolecules(fileContent); + deserializeToDrawingEntities( + fileContent: string, + centerPointOfCanvas?: Vec2, + ) { + const { + error: hasValidationErrors, + parsedFileContent, + structCenter, + } = this.parseAndValidateMacromolecules(fileContent); if (hasValidationErrors || !parsedFileContent) return; + const offset = Vec2.diff( + centerPointOfCanvas || new Vec2(0, 0), + structCenter, + ); const command = new Command(); const drawingEntitiesManager = new DrawingEntitiesManager(); const monomerIdsMap = {}; @@ -313,6 +339,7 @@ export class KetSerializer implements Serializer { template, struct, drawingEntitiesManager, + offset, ); const monomer = monomerAdditionCommand.operations[0] .monomer as BaseMonomer; diff --git a/packages/ketcher-polymer-editor-react/src/components/modal/Open/Open.tsx b/packages/ketcher-polymer-editor-react/src/components/modal/Open/Open.tsx index d51240426e..3d1d3abf3e 100644 --- a/packages/ketcher-polymer-editor-react/src/components/modal/Open/Open.tsx +++ b/packages/ketcher-polymer-editor-react/src/components/modal/Open/Open.tsx @@ -27,6 +27,8 @@ import { CoreEditor, KetcherLogger, EditorHistory, + Vec2, + Coordinates, } from 'ketcher-core'; import { IndigoProvider } from 'ketcher-react'; import assert from 'assert'; @@ -60,7 +62,13 @@ const addToCanvas = ({ editor: CoreEditor; struct: string; }) => { - const deserialisedKet = ketSerializer.deserializeToDrawingEntities(struct); + const centerPointOfCanvas = Coordinates.canvasToModel( + new Vec2(editor.canvasOffset.width / 2, editor.canvasOffset.height / 2), + ); + const deserialisedKet = ketSerializer.deserializeToDrawingEntities( + struct, + centerPointOfCanvas, + ); assert(deserialisedKet); deserialisedKet.drawingEntitiesManager.mergeInto( editor.drawingEntitiesManager,