diff --git a/package-lock.json b/package-lock.json index ea216551e54001f2306d37a6c4697534c7ccad25..90d7b1cd967236c86965649647be2f35e505c34d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "netex", - "version": "0.4.2", + "version": "0.7.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -7718,6 +7718,11 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", diff --git a/package.json b/package.json index c70ceff9643609436015c4be75cd49f51411d318..432707e80efe8da479a8a6bbe94ac24f3f8ec2c9 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "bulma-tooltip": "^3.0.2", "document-register-element": "^1.7.2", "dom-to-image": "^2.6.0", + "lodash.merge": "^4.6.2", "primeicons": "^4.1.0", "primeng": "^12.0.0-rc.1", "python": "0.0.4", diff --git a/src/app/components/network-legend/network-legend.component.ts b/src/app/components/network-legend/network-legend.component.ts index 28c4281444b378900d7433946ada165b9d31c128..64984b1ab62a0315250b000c8864ffee875ab5fa 100644 --- a/src/app/components/network-legend/network-legend.component.ts +++ b/src/app/components/network-legend/network-legend.component.ts @@ -13,6 +13,7 @@ export class NetworkLegendComponent implements OnInit { @Input() set config(value: IConfig) { // copy to not override user config value = JSON.parse(JSON.stringify(value)); + delete value.nodeGroups.selectedNode; if (!this.analysis) { // do not show the analysis-groups in the explorer network delete value.nodeGroups.foundNode; diff --git a/src/app/config.ts b/src/app/config.ts index 3dc540e6ca08f2ebf30dbd4a4fdf5b7cb84a94d3..7c29acf5218aa3e4c125465d9cc7913a8dc0591d 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -1,10 +1,16 @@ +// https://visjs.github.io/vis-network/docs/network/nodes.html export interface NodeGroup { groupName: string; - color: string; - shape: 'circle' | 'triangle' | 'star' | 'square' | 'image' | 'text' | 'ellipse' | 'box' | 'diamond' | 'dot'; - type: string; + color?: string; + shape?: 'circle' | 'triangle' | 'star' | 'square' | 'image' | 'text' | 'ellipse' | 'box' | 'diamond' | 'dot'; + type?: string; image?: string; detailShowLabel?: boolean; + font?: any; + border?: any; + highlight?: any; + borderWidth?: number; + borderWidthSelected?: number; } export interface EdgeGroup { @@ -86,6 +92,21 @@ export const defaultConfig: IConfig = { shape: 'triangle', type: 'default type', detailShowLabel: false, + font: { + color: 'black', + size: 14, + face: 'arial', + background: undefined, + strokeWidth: 0, + strokeColor: '#ffffff', + align: 'center', + bold: false, + ital: false, + boldital: false, + mono: false, + }, + borderWidth: 1, + borderWidthSelected: 3 }, foundNode: { groupName: 'Found Nodes', @@ -101,9 +122,33 @@ export const defaultConfig: IConfig = { }, seedNode: { groupName: 'Seed Nodes', - color: 'blue', - shape: 'circle', - type: 'seed', + // color: '#F8981D', + // shape: 'circle', + // type: 'seed', + border: '#F8981D', + highlight: { + border: '#F8981D', + background: '#F8981D' + }, + font: { + color: '#F8981D', + size: 14 + } + }, + selectedNode: { + groupName: 'Selected Nodes', + color: '#F8981D', + // shape: 'dot', + // type: 'selected', + border: '#F8981D', + highlight: { + border: '#F8981D', + background: '#F8981D' + }, + font: { + color: '#F8981D', + size: 14 + } } }, edgeGroups: { diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts index 818af38611b96a45f36dd29734143d4d806faa31..35d6ca2d3f7e7c112d64fcc8de25fe40e460f045 100644 --- a/src/app/interfaces.ts +++ b/src/app/interfaces.ts @@ -12,11 +12,16 @@ export interface Node { groupName?: string; color?: string | any; // mostly any, but vis js allows detail settings shape?: string; + image?: string; interactions?: Node[]; x?: number; y?: number; borderWidth: number; borderWidthSelected: number; + font: { + color: string; + size: number; + } } export interface Tissue { diff --git a/src/app/network-settings.ts b/src/app/network-settings.ts index 2a6ee9a334ff07710d17976e9490392df6d93da8..29b75b7453cf8c702170a6f7bb1dbd2267c3b5eb 100644 --- a/src/app/network-settings.ts +++ b/src/app/network-settings.ts @@ -3,6 +3,7 @@ import { Node, } from './interfaces'; import { IConfig, defaultConfig} from './config'; +import * as merge from 'lodash/fp/merge'; export class NetworkSettings { @@ -16,39 +17,15 @@ export class NetworkSettings { private static approvedDrugColor = '#48C774'; private static unapprovedDrugColor = '#F8981D'; private static nonSeedHostColor = '#3070B3'; - private static nonSeedVirusColor = '#87082c'; - - private static selectedBorderColor = '#F8981D'; - private static selectBorderHighlightColor = '#F8981D'; - - private static seedBorderColor = '#F8981D'; - private static seedBorderHighlightColor = '#F8981D'; // Edge color - private static edgeHostVirusColor = '#686868'; - private static edgeHostVirusHighlightColor = '#686868'; private static edgeHostDrugColor = '#686868'; private static edgeHostDrugHighlightColor = '#686868'; private static edgeGeneGeneColor = '#686868'; private static edgeGeneGeneHighlightColor = '#686868'; - - // Border width for nodes in selection - private static selectedBorderWidth = 3; - private static selectedBorderWidthSelected = 3; - // Border width for seed nodes - private static seedBorderWidth = 3; - private static seedBorderWidthSelected = 3; - // Border width - private static borderWidth = 1; - private static borderWidthSelected = 3; - - // Node Font - private static hostFontSize = 20; - private static drugFontSize = 30; private static hostFontColor = NetworkSettings.White; private static drugFontColor = NetworkSettings.White; - private static drugInTrialFontColor = NetworkSettings.Black; // Network Layout private static analysisLayout = { @@ -91,26 +68,6 @@ export class NetworkSettings { private static drugNotInTrialShape = 'box'; private static drugInTrialShape = 'triangle'; - // static getNodeSize(wrapperType: WrapperType) { - // if (wrapperType === 'protein') { - // return this.hostSize; - // } else if (wrapperType === 'drug') { - // return this.drugSize; - // } - // } - - // static getNodeShape(wrapperType: WrapperType, drugInTrial?: boolean) { - // if (wrapperType === 'protein') { - // return this.hostShape; - // } else if (wrapperType === 'drug') { - // if (drugInTrial) { - // return this.drugInTrialShape; - // } else { - // return this.drugNotInTrialShape; - // } - // } - // } - static getOptions(network: 'main' | 'analysis' | 'analysis-big') { if (network === 'main') { return { @@ -163,150 +120,43 @@ export class NetworkSettings { } } - // static getFont(wrapperType: WrapperType, drugInTrial?: boolean) { - // if (wrapperType === 'protein') { - // return {color: this.hostFontColor, size: this.hostFontSize}; - // } else if (wrapperType === 'drug') { - // if (!drugInTrial) { - // return {color: this.drugFontColor, size: this.drugFontSize}; - // } else { - // return {color: this.drugInTrialFontColor, size: this.drugFontSize}; - // } - // } - // } - static getNodeStyle( node: Node, config: IConfig, isSeed: boolean, isSelected: boolean, - drugType?: string, - drugInTrial?: boolean, gradient?: number): any { - if (!gradient) { - gradient = -1.0; - } - let nodeGroupObject; if (node.group === 'default') { - nodeGroupObject = defaultConfig.nodeGroups.default; - } else { - nodeGroupObject = config.nodeGroups[node.group]; - } - let nodeColor; - if (gradient === null) { - nodeColor = NetworkSettings.Grey; + console.log("we should not see this") + node = merge(node, defaultConfig.nodeGroups.default); } else { - nodeColor = getGradientColor(NetworkSettings.White, nodeGroupObject.color, gradient); + node = merge(node, config.nodeGroups[node.group]); } - // vis js style attributes - const nodeShadow = true; - // const nodeShape = node.shape; - // const nodeSize = 10; - // const nodeFont = node.font; - console.log("is selected") - console.log(isSelected) - + // note that seed and selected node style are applied after the node style is fetched. + // this allows to overwrite only attributes of interest, therefor in e.g. seedNode group + // certain attributes like shape can remain undefined if (isSeed) { - node.color = { - background: nodeColor, - border: this.seedBorderColor, - highlight: { - border: this.seedBorderHighlightColor, - background: nodeColor - } - }; - node.borderWidth = this.seedBorderWidth; - node.borderWidthSelected = this.seedBorderWidthSelected; + // apply seed node style to node + node = merge(node, config.nodeGroups.seedNode); } else if (isSelected) { - node.color = { - background: nodeColor, - border: this.selectedBorderColor, - highlight: { - border: this.selectBorderHighlightColor, - background: nodeColor - } - }; - node.borderWidth = this.selectedBorderWidth; - node.borderWidthSelected = this.selectedBorderWidthSelected; + // apply selected node style to node + console.log("node styles") + console.log(node) + console.log(config.nodeGroups.selectedNode) + node = merge(node, config.nodeGroups.selectedNode); + } + // show image if image url is given + if (node.image) { + node.shape = 'image'; + } + // calculate color gradient if gradient is givel + if (gradient === null) { + node.color = NetworkSettings.Grey; } else { - node.color = nodeColor; - node.borderWidth = this.borderWidth; - node.borderWidthSelected = this.borderWidthSelected; + node.color = getGradientColor(NetworkSettings.White, node.color, gradient); } return node; } - - // static getNodeStyleOld(nodeType: WrapperType, - // isSeed: boolean, - // isSelected: boolean, - // drugType?: string, - // drugInTrial?: boolean, - // gradient?: number): any { - // if (!gradient) { - // gradient = 1.0; - // } - // let nodeColor; - // let nodeShape; - // let nodeSize; - // let nodeFont; - // const nodeShadow = true; - // nodeShape = NetworkSettings.getNodeShape(nodeType); - // nodeSize = NetworkSettings.getNodeSize(nodeType); - // nodeFont = NetworkSettings.getFont(nodeType); - // if (nodeType === 'protein') { - // nodeColor = NetworkSettings.getColor(nodeType); - // nodeFont = NetworkSettings.getFont('protein'); - // if (!isSeed) { - // nodeColor = NetworkSettings.getColor('nonSeedHost'); - // } - // } else if (nodeType === 'drug') { - // if (drugType === 'approved') { - // nodeColor = NetworkSettings.getColor('approvedDrug'); - // } else { - // nodeColor = NetworkSettings.getColor('unapprovedDrug'); - // } - // if (drugInTrial) { - // nodeShape = NetworkSettings.getNodeShape('drug', true); - // nodeFont = NetworkSettings.getFont('drug', true); - // } else { - // nodeShape = NetworkSettings.getNodeShape('drug', false); - // } - // } - - // if (gradient === -1) { - // nodeColor = NetworkSettings.GREY; - // } else { - // nodeColor = getGradientColor(NetworkSettings.WHITE, nodeColor, gradient); - // } - - // const node: any = { - // size: nodeSize, - // shape: nodeShape, - // font: nodeFont, - // shadow: nodeShadow, - // }; - - // if (isSelected) { - // node.color = { - // background: nodeColor, - // border: this.selectedBorderColor, - // highlight: { - // border: this.selectBorderHighlightColor, - // background: nodeColor, - // }, - // }; - - // node.borderWidth = this.selectedBorderWidth; - // node.borderWidthSelected = this.selectedBorderWidthSelected; - // } else { - // node.color = nodeColor; - - // node.borderWidth = this.borderWidth; - // node.borderWidthSelected = this.borderWidthSelected; - // } - - // return node; - // } } diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index e3e82a64e8ad88cca0af258aa4ef252bd1c14970..6a8446849e15ad865f86b0fdbff70a72953c0253 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -21,6 +21,7 @@ import {NetworkSettings} from '../../network-settings'; import {defaultConfig, EdgeGroup, IConfig, InteractionDatabase, NodeGroup} from '../../config'; import {NetexControllerService} from 'src/app/services/netex-controller/netex-controller.service'; import {rgbaToHex, rgbToHex, standardize_color} from '../../utils' +import * as merge from 'lodash/fp/merge'; // import * as 'vis' from 'vis-network'; // import {DataSet} from 'vis-data'; // import {vis} from 'src/app/scripts/vis-network.min.js'; @@ -53,10 +54,10 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } // check if config updates affect network let updateNetworkFlag = false; - const configObj = JSON.parse(config); for (const key of Object.keys(configObj)) { if (key === 'nodeGroups') { + console.log("set node config") this.setConfigNodeGroup(key, configObj[key]); updateNetworkFlag = true; // dont set the key here, will be set in function @@ -107,7 +108,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { return; } this.networkJSON = network; - console.log(this.myConfig) this.createNetwork(); } @@ -419,20 +419,26 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { // stop if nodeGroups do not contain any information return; } - // // do not allow '_' in node Group names since it causes problems with backend // nodeGroups = removeUnderscoreFromKeys(nodeGroups) // make sure all keys are set Object.entries(nodeGroups).forEach(([key, group]) => { + if (!('color' in group)) { + // use detailShowLabel default value if not set + group['color'] = defaultConfig.nodeGroups.default.color; + } if (!('detailShowLabel' in group)) { // use detailShowLabel default value if not set group['detailShowLabel'] = defaultConfig.nodeGroups.default.detailShowLabel; } + if (!('font' in group)) { + // use detailShowLabel default value if not set + group['font'] = defaultConfig.nodeGroups.default.font; + } // color needs to be hexacode to calculate gradient if (!group.color.startsWith('#')) { // color is either rgba, rgb or string like "red" - console.log(group.color) if (group.color.startsWith('rgba')) { group.color = rgbaToHex(group.color).slice(0, 7) } else if (group.color.startsWith('rgb')) { @@ -440,7 +446,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } else ( group.color = standardize_color(group.color) ) - console.log(group.color) } }); @@ -449,8 +454,9 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { // if user has set nodeGroups, do not use group "default" delete defaultNodeGroups.default; // if user has not set the return-groups, take the defaults - nodeGroups = {...defaultNodeGroups, ...nodeGroups}; - // override default node groups + // user merge function to do deep merge + nodeGroups = merge(defaultNodeGroups, nodeGroups); + // overwrite default node groups this.myConfig[key] = nodeGroups; } @@ -536,7 +542,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } public selectTissue(tissue: Tissue | null) { - console.log("here") this.expressionExpanded = false; if (!tissue) { this.selectedTissue = null; diff --git a/src/index.html b/src/index.html index 8294d95a9c7b7e55a1f23107d2435af5a9197329..5225bf727c493fa542baf89397b474f6b5a3e756 100644 --- a/src/index.html +++ b/src/index.html @@ -35,7 +35,7 @@ <network-expander id="netexp1" config='{ - "nodeGroups": {"0.5": {"type": "0.5er Instanz", "color": "green", "groupName": "0.5", "shape": "hexagon"}, "patientgroup": {"type": "Patient", "detailShowLabel": "true", "color": "#632345", "groupName": "patient group", "shape": "dot", "size": "50"}, "pugGroup": {"type": "woof woof", "color": "grey", "groupName": "Pug Group", "shape": "triangle", "image": "https://static.raymondcamden.com/images/2016/11/pug.png"}}, + "nodeGroups": {"selectedNode": {"font": {"size": "18"} }, "0.5": {"font": "18px verdana blue", "type": "0.5er Instanz", "color": "green", "groupName": "0.5", "shape": "hexagon"}, "patientgroup": {"type": "Patient", "detailShowLabel": "true", "color": "#632345", "groupName": "patient group", "shape": "dot", "size": "50"}, "pugGroup": {"type": "woof woof", "color": "grey", "groupName": "Pug Group", "shape": "triangle", "image": "https://static.raymondcamden.com/images/2016/11/pug.png"}}, "edgeGroups": {"dashes": {"color": "black", "groupName": "dashes Group", "dashes": [1, 2]}, "notdashes": {"color": "black", "groupName": "not dashes Group"}}, "identifier": "symbol" }'