UNPKG

ngx-cytoscapejs

Version:
1 lines 17.2 kB
{"version":3,"file":"ngx-cytoscapejs.mjs","sources":["../../../projects/ngx-cytoscapejs/src/lib/enum/cx-converter.enum.ts","../../../projects/ngx-cytoscapejs/src/lib/service/cx.service.ts","../../../projects/ngx-cytoscapejs/src/lib/component/cytoscapejs.component.ts","../../../projects/ngx-cytoscapejs/src/lib/component/cytoscapejs.component.html","../../../projects/ngx-cytoscapejs/src/public-api.ts","../../../projects/ngx-cytoscapejs/src/ngx-cytoscapejs.ts"],"sourcesContent":["/**\n * Available libraries to convert from CX to Cytoscape.js.\n */\nexport enum CxConverter {\n cx2js = 'cx2js',\n cxVizConverter = 'cxVizConverter',\n}\n","/* eslint-disable class-methods-use-this */\nimport { Injectable } from '@angular/core';\nimport { CytoscapeOptions } from 'cytoscape';\n// @ts-expect-error no types available\nimport { convert } from '@js4cytoscape/cx-viz-converter';\n// @ts-expect-error no types available\nimport { CyNetworkUtils, CxToJs } from 'cytoscape-cx2js';\nimport { CxConverter } from '../enum/cx-converter.enum';\nimport { CxConversion } from '../interface/cx-conversion.interface';\n\n/**\n * This service handles the conversion from CX to Cytoscape.js graphs.\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class CxService {\n /**\n * Tries to convert the incoming CX object into CytoscapeOptions using the list of {@link CxConverter}s in sequence.\n *\n * @param {any} cxData CX object\n * @param {CxConverter[]} converters List of {@link CxConverter}s\n * @returns {CxConversion | null} On success the resulting CxConversion object is returned, otherwise null is returned.\n */\n convert(cxData: any, converters: CxConverter[]): CxConversion | null {\n if (cxData && converters) {\n for (let i = 0; i < converters.length; i += 1) {\n let conversion: CxConversion | null = null;\n\n switch (converters[i]) {\n case CxConverter.cx2js:\n conversion = this.convertWithCx2JS(cxData);\n break;\n case CxConverter.cxVizConverter:\n conversion = this.convertWithCxVizConverter(cxData);\n break;\n default:\n break;\n }\n\n if (conversion) {\n return conversion;\n }\n }\n }\n\n return null;\n }\n\n /**\n * Tries to convert the input CX object using [cx2js]{@link https://github.com/cytoscape/cx2js}.\n *\n * @param {any} cxData CX object\n * @returns {CxConversion | null} On success the converted CytoscapeOptions object as well as the attributeNameMap object is returned, otherwise null is returned.\n */\n private convertWithCx2JS(cxData: any): CxConversion | null {\n try {\n const utils = new CyNetworkUtils();\n const niceCX = utils.rawCXtoNiceCX(cxData);\n const cx2Js = new CxToJs(utils);\n const attributeNameMap = {};\n const elements = cx2Js.cyElementsFromNiceCX(niceCX, attributeNameMap);\n const style = cx2Js.cyStyleFromNiceCX(niceCX, attributeNameMap);\n const layout = cx2Js.getDefaultLayout();\n const zoom = cx2Js.cyZoomFromNiceCX(niceCX);\n const pan = cx2Js.cyPanFromNiceCX(niceCX);\n const backgroundColor = cx2Js.cyBackgroundColorFromNiceCX(niceCX);\n\n const options: CytoscapeOptions = { elements, style, layout, zoom, pan };\n const conversion: CxConversion = {\n options,\n attributeNameMap,\n backgroundColor,\n };\n\n return conversion;\n } catch (error) {\n console.error(error);\n }\n\n return null;\n }\n\n /**\n * Tries to convert the input CX object using [cx-viz-converter]{@link https://github.com/cytoscape/cx-viz-converter}.\n *\n * @param {any} cxData CX object\n * @returns {CytoscapeOptions | null} On success the converted CytoscapeOptions object is returned, otherwise null is returned.\n */\n private convertWithCxVizConverter(cxData: any): CxConversion | null {\n try {\n const options: CytoscapeOptions = convert(cxData, 'cytoscapeJS');\n const conversion: CxConversion = { options };\n\n return conversion;\n } catch (error) {\n console.error(error);\n }\n\n return null;\n }\n}\n","import {\n AfterViewInit,\n Component,\n ElementRef,\n EventEmitter,\n inject,\n Input,\n OnChanges,\n OnDestroy,\n Output,\n SimpleChanges,\n ViewChild,\n} from '@angular/core';\nimport cytoscape, { Core, CytoscapeOptions } from 'cytoscape';\nimport { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs';\nimport { CxAttributeNameMap } from '../interface/cx-attribute-name-map.interface';\nimport { CxConverter } from '../enum/cx-converter.enum';\nimport { CxService } from '../service/cx.service';\n\n/**\n * This component handles rendering the Cytoscape.js graph.\n */\n@Component({\n selector: 'cytoscapejs',\n standalone: true,\n templateUrl: './cytoscapejs.component.html',\n styleUrl: './cytoscapejs.component.scss',\n})\nexport class CytoscapejsComponent\n implements AfterViewInit, OnChanges, OnDestroy\n{\n /**\n * Object containing information about a graph. Must conform to [CytoscapeOptions]{@link https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/cytoscape/index.d.ts}. A specified container is ignored.\n * Should not be defined, if you are using {@link cxData} to build a graph.\n */\n @Input() cytoscapeOptions!: CytoscapeOptions;\n\n /**\n * Responsible for automatically resizing the graph when the browser window changes its size.\n * If true, resizing the graph is triggered.\n * If false, changes in window size are ignored.\n */\n @Input() autoFit: boolean = true;\n\n /**\n * Responsible for applying the background color specified in the CX file to the canvas.\n * If true, the network's background color will be set to the color specified in the CX.\n * If false, the network's background color will be white.\n */\n @Input() applyCxBackgroundColor: boolean = false;\n\n /**\n * Object containing information about a graph. Must conform to [CX data model]{@link https://home.ndexbio.org/data-model/}.\n * Should not be defined, if you are using {@link cytoscapeOptions} to build a graph.\n */\n @Input() cxData!: any;\n\n /**\n * List of {@link CxConverter}s you wish to use for conversion of your {@link cxData}.\n * Arrange the converters in the order, in which they are to be executed, e.g. the first converter you specify will be tried first.\n * The first successful conversion result will be rendered.\n */\n @Input() cxConverters: CxConverter[] = [\n CxConverter.cx2js,\n CxConverter.cxVizConverter,\n ];\n\n /**\n * Each time a new [Cytoscape.js core]{@link https://js.cytoscape.org/#core} is built, this output is firing an event containing the recent core.\n */\n @Output() coreChanged: EventEmitter<Core> = new EventEmitter<Core>();\n\n /**\n * Each time a new [Cytoscape.js core]{@link https://js.cytoscape.org/#core} is built using [cx2js]{@link https://github.com/cytoscape/cx2js} the\n * resulting attributeNameMap object is emitted as well.\n */\n @Output() cxAttributeNameMapChanged: EventEmitter<CxAttributeNameMap> =\n new EventEmitter<CxAttributeNameMap>();\n\n /**\n * Reference to the HTMLElement that is used as a [container]{@link https://js.cytoscape.org/#core/initialisation} for the graph.\n *\n * @internal\n */\n @ViewChild('cy') cyElementRef!: ElementRef;\n\n /**\n * Represents a state in the [Angular lifecycle]{@link https://angular.io/guide/lifecycle-hooks} indicating, that the view has been initialized.\n *\n * @internal\n */\n private isViewInitialized: boolean = false;\n\n /**\n * [Cytoscape.js core]{@link https://js.cytoscape.org/#core} that is rendered.\n *\n * @internal\n */\n private core!: Core;\n\n /**\n * Serves as an indicator, when the component has been destroyed.\n *\n * @internal\n */\n private destroy$: Subject<boolean> = new Subject<boolean>();\n\n /**\n * Service responsible for conversion\n *\n * @internal\n */\n private cxService = inject(CxService);\n\n /**\n * [Angular lifecycle]{@link https://angular.io/guide/lifecycle-hooks} which is called as soon as the view has been initialized.\n * Used to subscribe to any window resize event. Triggers initial rendering.\n */\n ngAfterViewInit(): void {\n fromEvent(window, 'resize')\n .pipe(takeUntil(this.destroy$), debounceTime(300))\n .subscribe(() => this.fit());\n\n this.isViewInitialized = true;\n this.preRender();\n }\n\n /**\n * [Angular lifecycle]{@link https://angular.io/guide/lifecycle-hooks} which is called every time, an input property changes its value.\n * Used to update the graph's visualization.\n *\n * @param {SimpleChanges} changes Object containing all changes\n */\n ngOnChanges(changes: SimpleChanges): void {\n const { cytoscapeOptions, cxData, autoFit } = changes;\n\n if (cytoscapeOptions || cxData) {\n this.preRender();\n }\n\n if (autoFit) {\n this.fit();\n }\n }\n\n /**\n * [Angular lifecycle]{@link https://angular.io/guide/lifecycle-hooks} which is called as soon as the component is destroyed.\n * Used to unsubscribe from window resize events.\n */\n ngOnDestroy(): void {\n this.destroy$.next(true);\n this.destroy$.complete();\n }\n\n /**\n * Based on the user's input, this method decides, if rendering can happen and which input is to be used.\n */\n private preRender(): void {\n if (!this.isViewInitialized || (!this.cytoscapeOptions && !this.cxData)) {\n return;\n }\n\n if (this.cytoscapeOptions) {\n this.render(this.cytoscapeOptions);\n } else if (this.cxData) {\n const conversion = this.cxService.convert(this.cxData, this.cxConverters);\n\n if (conversion) {\n const { options, attributeNameMap, backgroundColor } = conversion;\n\n if (this.cyElementRef && this.cyElementRef.nativeElement) {\n const htmlElement: HTMLElement = this.cyElementRef.nativeElement;\n\n if (this.applyCxBackgroundColor && backgroundColor) {\n htmlElement.style.backgroundColor = backgroundColor;\n } else {\n htmlElement.style.backgroundColor = '';\n }\n }\n\n this.cxAttributeNameMapChanged.emit(attributeNameMap);\n\n if (options) {\n this.render(options);\n }\n }\n }\n }\n\n /**\n * Renders the graph using [CytoscapeOptions]{@link https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/cytoscape/index.d.ts}.\n *\n * @param {CytoscapeOptions} options Object containing graph information\n */\n private render(options: CytoscapeOptions): void {\n if (options) {\n this.core = cytoscape({\n ...options,\n container: this.cyElementRef.nativeElement,\n });\n this.core.fit();\n this.coreChanged.emit(this.core);\n }\n }\n\n /**\n * Resizes and repositions the graph to fit the current window size.\n */\n private fit(): void {\n if (this.autoFit && this.core) {\n this.core.fit();\n }\n }\n}\n","<div id=\"cy\" #cy></div>\n","/*\n * Public API Surface of ngx-cytoscapejs\n */\n\nexport * from './lib/component/cytoscapejs.component';\nexport * from './lib/enum/cx-converter.enum';\nexport * from './lib/interface/cx-attribute-name-map.interface';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}