From f3db601082b2957e30d1573343e739c2fa220be1 Mon Sep 17 00:00:00 2001 From: Adam Wright Date: Sat, 3 Oct 2026 04:35:17 +0000 Subject: [PATCH] Keep the cytoscape style's copy in step with ngx-reactome-base The same fixes as reactome/ngx-reactome-base#1, so this copy and that one stay identical until the site installs the library from there: - package.json declares what the library imports (cytoscape, cytoscape-layers 3, chroma-js, lodash), not lodash.memoize, which it never imports; its hand-written `exports`, which named files no build makes, is gone (ng-packagr writes the right ones); ng-package.json no longer lists a `types` folder that does not exist; - drawer/types.ts imports cytoscape's types instead of relying on the global namespace; - a molecule's structure still loading is recognised as a thenable, not through rxjs's internal isPromise; one that fails to load removes its container (it was awaited with no rejection handler); - a structure that cannot be shown removes only the four background properties it set, not all of the node's inline style -- the zoom's opacity went with it, hiding trivial molecules until the next zoom. And in the diagram service: an entity type with no mapping spread its name into one class per letter; it is one class now. Co-Authored-By: Claude Opus 5.5 --- .../src/app/services/diagram.service.ts | 4 ++- .../reactome-cytoscape-style/ng-package.json | 5 ---- .../reactome-cytoscape-style/package.json | 18 ++++-------- .../src/lib/drawer/types.ts | 5 ++-- .../src/lib/interactivity.ts | 28 +++++++++++++++---- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/projects/pathway-browser/src/app/services/diagram.service.ts b/projects/pathway-browser/src/app/services/diagram.service.ts index 1e4cad67..8540139a 100644 --- a/projects/pathway-browser/src/app/services/diagram.service.ts +++ b/projects/pathway-browser/src/app/services/diagram.service.ts @@ -483,7 +483,9 @@ export class DiagramService { //entity nodes const entityNodes: cytoscape.NodeDefinition[] = diagram?.nodes.flatMap((item) => { let classes = [ - ...(this.nodeTypeMap.get(item.renderableClass) || item.renderableClass.toLowerCase()), + // An array: spreading the bare string spread an unknown type's name + // into one class per letter. + ...(this.nodeTypeMap.get(item.renderableClass) || [item.renderableClass.toLowerCase()]), ]; let unitId = undefined; if (item.schemaClass === SchemaClasses.POLYMER) { diff --git a/projects/reactome-cytoscape-style/ng-package.json b/projects/reactome-cytoscape-style/ng-package.json index e7a098b4..ce6db2d5 100644 --- a/projects/reactome-cytoscape-style/ng-package.json +++ b/projects/reactome-cytoscape-style/ng-package.json @@ -5,11 +5,6 @@ "entryFile": "src/public-api.ts" }, "assets": [ - { - "input": "types", - "glob": "*", - "output": "**/*" - }, { "input": "src/assets/", "glob": "**/*", diff --git a/projects/reactome-cytoscape-style/package.json b/projects/reactome-cytoscape-style/package.json index 867b6d0a..fa1f5c0b 100644 --- a/projects/reactome-cytoscape-style/package.json +++ b/projects/reactome-cytoscape-style/package.json @@ -4,22 +4,16 @@ "type": "module", "peerDependencies": { "cytoscape": "^3.30.0", - "lodash.memoize": "^4.1.2", - "chroma-js": "^3.1.2" + "cytoscape-layers": "^3.0.0", + "chroma-js": "^3.1.2", + "lodash": "^4.17.21" }, "dependencies": { "tslib": "^2.3.0" }, "devDependencies": { - "@types/chroma-js": "^3.1.1" + "@types/chroma-js": "^3.1.1", + "@types/lodash": "^4.17.0" }, - "sideEffects": false, - "exports": { - ".": { - "types": "./index.d.ts", - "esm2022": "./esm2022/reactome-cytoscape-style.mjs", - "esm": "./esm2022/reactome-cytoscape-style.mjs", - "default": "./fesm2022/reactome-cytoscape-style.mjs" - } - } + "sideEffects": false } diff --git a/projects/reactome-cytoscape-style/src/lib/drawer/types.ts b/projects/reactome-cytoscape-style/src/lib/drawer/types.ts index ab5c241e..dd3b5139 100644 --- a/projects/reactome-cytoscape-style/src/lib/drawer/types.ts +++ b/projects/reactome-cytoscape-style/src/lib/drawer/types.ts @@ -1,5 +1,6 @@ -import BackgroundImage = cytoscape.Css.BackgroundImage; -import PropertyValueNode = cytoscape.Css.PropertyValueNode; +import type cytoscape from 'cytoscape'; +type BackgroundImage = cytoscape.Css.BackgroundImage; +type PropertyValueNode = cytoscape.Css.PropertyValueNode; import _ from 'lodash'; import { Properties } from '../properties'; diff --git a/projects/reactome-cytoscape-style/src/lib/interactivity.ts b/projects/reactome-cytoscape-style/src/lib/interactivity.ts index 12f8a8a5..895b1b9f 100644 --- a/projects/reactome-cytoscape-style/src/lib/interactivity.ts +++ b/projects/reactome-cytoscape-style/src/lib/interactivity.ts @@ -4,7 +4,6 @@ import { Properties } from './properties'; import { ReactomeEvent, ReactomeEventTypes } from './model/reactome-event.model'; import Layers, { IHTMLLayer, layers, LayersPlugin } from 'cytoscape-layers'; import * as _ from 'lodash'; -import { isPromise } from 'rxjs/internal/util/isPromise'; cytoscape.use(Layers); type RenderableHTMLElement = HTMLElement & { @@ -427,7 +426,17 @@ export class Interactivity { // console.log('Remove diagram structure container because not found', loadingContainer, node) loadingContainer.classList.remove('loading'); this.removeLoading(loadingContainer); - node.removeStyle(); + // Only what the structure set. All of the node's inline style went before, + // the zoom's opacity with it, and a trivial molecule then fell back to its + // stylesheet opacity of 0 until the next zoom -- which never came in a + // diagram that cannot be zoomed. + for (const property of [ + 'background-position-x', + 'background-position-y', + 'background-width', + 'background-height', + ]) + node.removeStyle(property); this.structureContainers = this.structureContainers.not(node); } @@ -456,7 +465,8 @@ export class Interactivity { elem.style.height = h - 2 * margin + 'px'; elem.style.display = 'flex'; - const structure = node.data('chebiStructure') as string; + // The structure's SVG, or its load while it is still on the way. + const structure = node.data('chebiStructure') as string | PromiseLike; const initStructure = (svgData: string) => { if (svgData === undefined) return this.removeStructureContainer(elem, node); elem.innerHTML = svgData; @@ -476,10 +486,16 @@ export class Interactivity { this.removeLoading(elem); }; - if (isPromise(structure)) { - structure.then(initStructure); + // A thenable -- not `instanceof Promise`, which is false for a native + // promise where zone.js has replaced the global, as in an app that + // uses it -- and not rxjs's internal isPromise, no part of its API. + if (typeof (structure as PromiseLike)?.then === 'function') { + // A structure that fails to load is one that could not be found. + (structure as PromiseLike).then(initStructure, () => + this.removeStructureContainer(elem, node) + ); } else { - initStructure(structure); + initStructure(structure as string); } }, transform: `translate(-100%, -50%)`,