diff --git a/src/app/utils.ts b/src/app/utils.ts index 45f95c90d82c2c754e3668ec141a7296e55ecc2b..7cbf2ceb031bdef99f355cef4efa8ddff4c05bc5 100644 --- a/src/app/utils.ts +++ b/src/app/utils.ts @@ -89,7 +89,7 @@ export function rgbaToHex(rgba) { // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb function componentToHex(c) { const hex = c.toString(16); - return hex.length == 1 ? '0' + hex : hex; + return hex.length === 1 ? '0' + hex : hex; } export function rgbToHex(rgb) { @@ -100,6 +100,14 @@ export function rgbToHex(rgb) { return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b); } +export function rgbaWithoutAToHex(rgb) { + const inParts = rgb.substring(rgb.indexOf('(')).split(','), + r = parseInt(trim(inParts[0].substring(1)), 10), + g = parseInt(trim(inParts[1]), 10), + b = parseInt(trim(inParts[2]), 10); + return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b); +} + // https://stackoverflow.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes/47355187#47355187 export function standardizeColor(str) { var ctx = document.createElement('canvas').getContext('2d'); @@ -144,41 +152,79 @@ export function RGBAtoRGBwithoutA(rgbaString) { return `rgb(${RGBA.red},${RGBA.green},${RGBA.blue})`; } -export function RGBAtoRGB(rgbaString) { +function hexToRGBA(hex, alpha) { + let r; + let g; + let b; + if (hex.length < 5) { + r = parseInt(hex.slice(1, 2) + hex.slice(1, 2), 16); + g = parseInt(hex.slice(2, 3) + hex.slice(2, 3), 16); + b = parseInt(hex.slice(3, 4) + hex.slice(3, 4), 16); + } else { + r = parseInt(hex.slice(1, 3), 16); + g = parseInt(hex.slice(3, 5), 16); + b = parseInt(hex.slice(5, 7), 16); + } + if (alpha) { + return 'rgba(' + (isNaN(r) ? 0 : r) + ', ' + (isNaN(g) ? 0 : g) + ', ' + (isNaN(b) ? 0 : b) + ', ' + alpha + ')'; + } else { + return 'rgb(' + (isNaN(r) ? 0 : r) + ', ' + isNaN(g) ? 0 : g + ', ' + isNaN(b) ? 0 : b + ')'; + } +} + +// https://gist.github.com/JordanDelcros/518396da1c13f75ee057?permalink_comment_id=2075095#gistcomment-2075095 +export function blendColors(args: any) { + let base = [0, 0, 0, 0]; + let mix; + for (let added of args) { + added = RGBAtoArray(added); + if (typeof added[3] === 'undefined') { + added[3] = 1; + } + // check if both alpha channels exist. + if (base[3] && added[3]) { + mix = [0, 0, 0, 0]; + // alpha + mix[3] = 1 - (1 - added[3]) * (1 - base[3]); + // red + mix[0] = Math.round((added[0] * added[3] / mix[3]) + (base[0] * base[3] * (1 - added[3]) / mix[3])); + // green + mix[1] = Math.round((added[1] * added[3] / mix[3]) + (base[1] * base[3] * (1 - added[3]) / mix[3])); + // blue + mix[2] = Math.round((added[2] * added[3] / mix[3]) + (base[2] * base[3] * (1 - added[3]) / mix[3])); + + } else if (added) { + mix = added; + } else { + mix = base; + } + base = mix; + } + + return 'rgba(' + mix[0] + ', ' + mix[1] + ', ' + mix[2] + ', ' + mix[3] + ')'; +} + +export function RGBAtoArray(rgbaString) { const rgbaStringSplit = rgbaString.slice(5, -1).split(','); - const RGBA = { - red: rgbaStringSplit[0], - green: rgbaStringSplit[1], - blue: rgbaStringSplit[2], - alpha: rgbaStringSplit[3] - }; - // assume white background - const bg = {red: 255, green: 255, blue: 255}; - const RGB = {red: undefined, green: undefined, blue: undefined}; - const alpha = 1 - RGBA.alpha; - RGB.red = Math.round((RGBA.alpha * (RGBA.red / 255) + (alpha * (bg.red / 255))) * 255); - RGB.green = Math.round((RGBA.alpha * (RGBA.green / 255) + (alpha * (bg.green / 255))) * 255); - RGB.blue = Math.round((RGBA.alpha * (RGBA.blue / 255) + (alpha * (bg.blue / 255))) * 255); - return `rgb(${RGB.red},${RGB.green},${RGB.blue})`; + return [ + rgbaStringSplit[0], + rgbaStringSplit[1], + rgbaStringSplit[2], + rgbaStringSplit[3] + ]; } + export function pieChartContextRenderer({ctx, x, y, state: {selected, hover}, style, label}) { ctx.drawPieLabel = function(style, x, y, label) { ctx.font = 'normal 12px sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; - ctx.fillStyle = 'black'; + ctx.fillStyle = window.getComputedStyle(document.documentElement).getPropertyValue('--drgstn-text-primary'); ctx.fillText(label, x, y + style.size + 12); }; - ctx.drawPie = function(style, x, y, state: { selected, hover }) { - const selection = RGBAtoRGBwithoutA(style.borderColor) !== RGBAtoRGBwithoutA(style.color); - const total = 1; - // draw shadow - const selectedColor = style.borderColor; - if (selected) { - style.borderColor = style.color; - } + function startShadow() { if (style.shadow) { ctx.save(); ctx.shadowColor = style.shadowColor; @@ -186,60 +232,67 @@ export function pieChartContextRenderer({ctx, x, y, state: {selected, hover}, st ctx.shadowOffsetY = style.shadowY; ctx.shadowBlur = 10; } - // draw white background circle + } + + function endShadow() { + if (style.shadow) { + // removing shadow application of future fill or stroke calls + ctx.restore(); + } + } + + ctx.drawPie = function(style, x, y, state: { selected, hover }) { + const selection = RGBAtoRGBwithoutA(style.borderColor) !== RGBAtoRGBwithoutA(style.color); + const bgOpacity = 0.15; + const fgOpacity = 0.5; + const lineOpacity = 0.6; + const fullCircle = 2 * Math.PI; + const fallbackColor = '#FF0000'; + const colorOrFallback = style.color ? style.color : fallbackColor; + let outerBorderColor = style.borderColor; + if (selection) { + outerBorderColor = style.borderColor ? rgbaWithoutAToHex(style.borderColor) : fallbackColor; + } + if (selected) { + style.borderColor = style.color; + } + ctx.beginPath(); - ctx.fillStyle = 'white'; - // or fill like background of graph panel - // ctx.fillStyle= window.getComputedStyle(document.documentElement).getPropertyValue('--drgstn-panel'); ctx.arc(x, y, style.size - 1, 0, 2 * Math.PI, false); + // fill like background of graph panel + ctx.fillStyle = RGBAtoRGBwithoutA(blendColors([hexToRGBA(window.getComputedStyle(document.documentElement).getPropertyValue('--drgstn-panel'), 1), hexToRGBA(colorOrFallback, bgOpacity)])); + startShadow(); ctx.fill(); + endShadow(); ctx.stroke(); // prepare pi-chart - ctx.fillStyle = style.color ? style.color : 'rgba(255, 0, 0, 1)'; - // set alpha value to 1 - ctx.fillStyle = RGBAtoRGB(ctx.fillStyle); + ctx.fillStyle = hexToRGBA(colorOrFallback, fgOpacity); + ctx.beginPath(); ctx.moveTo(x, y); - const len = style.opacity / total * 2 * Math.PI; - ctx.arc(x, y, style.size - 1, 0, len, false); - ctx.lineTo(x, y); + ctx.arc(x, y, style.size - 1, 0, style.opacity * fullCircle, false); ctx.fill(); - if (style.shadow) { - // removing shadow application of future fill or stroke calls - ctx.restore(); - } - ctx.strokeStyle = style.borderColor ? style.borderColor : 'black'; - if (selection) { - ctx.strokeStyle = selectedColor ? selectedColor : 'balck'; - } + ctx.lineTo(x, y); + ctx.lineWidth = selected ? 3 : 2; - if (style.opacity !== total) { + if (style.opacity < 1) { // avoid the inner line when circle is complete + ctx.strokeStyle = hexToRGBA(outerBorderColor, lineOpacity); ctx.stroke(); } - ctx.strokeStyle = RGBAtoRGBwithoutA(ctx.strokeStyle); - // draw the surrounding border circle + // draw outer circle + ctx.strokeStyle = outerBorderColor; ctx.beginPath(); - ctx.arc(x, y, style.size - (selected ? 0 : 1), 0, 2 * Math.PI); - // ctx.strokeStyle = style.borderColor ? style.borderColor : 'black'; - // // set alpha value to 1 - // ctx.strokeStyle = RGBAtoRGBwithoutA(ctx.strokeStyle); + ctx.arc(x, y, style.size - (selected ? 0 : 1), 0, fullCircle); ctx.stroke(); - if (selection) { - ctx.strokeStyle = selectedColor ? selectedColor : 'black'; - } else { - ctx.strokeStyle = style.color ? style.color : 'black'; - } + + // draw inner circle (double circle if selected) if (selected || selection) { ctx.beginPath(); - ctx.strokeStyle = style.color ? style.color : 'black'; - ctx.strokeStyle = RGBAtoRGBwithoutA(ctx.strokeStyle); - ctx.arc(x, y, style.size - 2, 0, 2 * Math.PI); - // ctx.strokeStyle = style.borderColor ? style.borderColor : 'black'; - // // set alpha value to 1 - // ctx.strokeStyle = RGBAtoRGBwithoutA(ctx.strokeStyle); + ctx.strokeStyle = hexToRGBA(colorOrFallback, lineOpacity); + ctx.arc(x, y, style.size - 2, 0, fullCircle); ctx.stroke(); } }; diff --git a/src/index.html b/src/index.html index 52ec8c03e828afa9ad86245edb5fe192103c1ae7..f622bcde7c77ba73317fdeab2d126189b9d75e05 100644 --- a/src/index.html +++ b/src/index.html @@ -59,7 +59,7 @@ Export As Graphml Button<br> <br> <br> <b>Datasets</b> -<input type="checkbox" onclick=changeLicenced(this.checked)/> Use licenced datasets<br> +<input type="checkbox" onclick=changeLicenced(this.checked)> Use licenced datasets<br> <div> <i>Protein-Protein Interactions</i> <select name="Protein-Protein Interactions" onchange="applyDataset()" id="ppi-dataset"> @@ -111,8 +111,8 @@ Export As Graphml Button<br> <div style="max-width: 80vw; width: 1276px; height: 500px"> <drugst-one id="tatata" - groups='{ "nodeGroups" : { "selectedNode": { "borderWidth": 3,"borderWidthSelected": 4,"color": { "border": "#ff1818","highlight": {"border": "#ff1818"}},"font": { "color": "#F8981","size": 14 }},"Protein":{"shape":"circle","groupName":"Protein","type":"Protein","color":"#172b4d","font":{"color":"#ffffff"}}}}' - config='{"identifier":"symbol","title":"ROBUST output network", "taskDrugName": "Drug Search", "showLegendNodes": true, "showLegendEdges": true, "showSidebar": "left", "showOverview": true, "legendPos": "left", "legendClass": "legend", "showQuery": true, "showItemSelector": true,"showSimpleAnalysis": false,"showAdvAnalysis": true,"showSelection": true,"showTasks": true,"showNetworkMenu": "right","showLegend": true,"showNetworkMenuButtonExpression": true, "showNetworkMenuButtonScreenshot": true,"showNetworkMenuButtonExportGraphml": true,"showNetworkMenuButtonAdjacentDrugs": true,"showNetworkMenuButtonCenter": true,"showConnectGenes": false,"networkMenuButtonAdjacentDrugsLabel": "Drugs","showNetworkMenuButtonAdjacentDisordersProteins": true,"networkMenuButtonAdjacentDisordersProteinsLabel": "Disorders (protein)","showNetworkMenuButtonAdjacentDisordersDrugs": true,"networkMenuButtonAdjacentDisordersDrugsLabel": "Disorders (drug)","showNetworkMenuButtonAnimation": true,"networkMenuButtonAnimationLabel": "Animation", "autofillEdges": true, "physicsOn": false,"useNedrexLicenced": true,"selfReferences": false, "interactionDrugProtein": "NeDRex", "indicationDrugDisorder": "NeDRex","nodeShadow": true,"edgeShadow": true, "algorithms": {"drug": ["trustrank", "closeness", "degree", "proximity"], "drug-target": ["trustrank", "multisteiner", "keypathwayminer", "degree", "closeness", "betweenness"]}, "associatedProteinDisorder": "NeDRex", "expandNetworkMenu": true}' + groups='{ "edgeGroups":{"default":{"color":"#000000","groupName":"default edge"}}, "nodeGroups" : { "selectedNode": { "borderWidth": 3,"borderWidthSelected": 4,"color": { "border": "#C80BFD","highlight": {"border": "#C80BFD"}},"font": { "color": "#0000000","size": 14 }},"Protein":{"shape":"circle","groupName":"Protein","type":"Protein","color":"#C99AFFFF","font":{"color":"#FFFFFF"}}}}' + config='{"identifier":"symbol","title":"ROBUST output network", "taskDrugName": "Drug Search", "showLegendNodes": true, "showLegendEdges": true, "showSidebar": "left", "showOverview": true, "legendPos": "left", "legendClass": "legend", "showQuery": true, "showItemSelector": true,"showSimpleAnalysis": false,"showAdvAnalysis": true,"showSelection": true,"showTasks": true,"showNetworkMenu": "right","showLegend": true,"showNetworkMenuButtonExpression": true, "showNetworkMenuButtonScreenshot": true,"showNetworkMenuButtonExportGraphml": true,"showNetworkMenuButtonAdjacentDrugs": true,"showNetworkMenuButtonCenter": true,"showConnectGenes": false,"networkMenuButtonAdjacentDrugsLabel": "Drugs","showNetworkMenuButtonAdjacentDisordersProteins": true,"networkMenuButtonAdjacentDisordersProteinsLabel": "Disorders (protein)","showNetworkMenuButtonAdjacentDisordersDrugs": true,"networkMenuButtonAdjacentDisordersDrugsLabel": "Disorders (drug)","showNetworkMenuButtonAnimation": true,"networkMenuButtonAnimationLabel": "Animation", "autofillEdges": true, "physicsOn": false,"useNedrexLicenced": true,"selfReferences": false, "interactionDrugProtein": "NeDRex", "indicationDrugDisorder": "NeDRex","nodeShadow": true,"edgeShadow": false, "algorithms": {"drug": ["trustrank", "closeness", "degree", "proximity"], "drug-target": ["trustrank", "multisteiner", "keypathwayminer", "degree", "closeness", "betweenness"]}, "associatedProteinDisorder": "NeDRex", "expandNetworkMenu": true}' network='{"nodes": [{"id":"PSEN1","group":"Protein","label":"PSEN1"},{"id":"PSEN2","group":"Protein","label":"PSEN2"},{"id":"APP","group":"Protein","label":"APP"},{"id":"APOE","group":"Protein","label":"APOE"},{"id":"RNF32","group":"Protein","label":"RNF32"},{"id":"STX5","group":"Protein","label":"STX5"},{"id":"TRAF3IP1","group":"Protein","label":"TRAF3IP1"},{"id":"PHB1","group":"Protein","label":"PHB1"},{"id":"MAPT","group":"Protein","label":"MAPT"},{"id":"ESR1","group":"Protein","label":"ESR1"},{"id":"IRF3","group":"Protein","label":"IRF3"},{"id":"DYNC1H1","group":"Protein","label":"DYNC1H1"},{"id":"CUL3","group":"Protein","label":"CUL3"},{"id":"HMGB1","group":"Protein","label":"HMGB1"},{"id":"DNAJC7","group":"Protein","label":"DNAJC7"},{"id":"NEFM","group":"Protein","label":"NEFM"},{"id":"DISC1","group":"Protein","label":"DISC1"},{"id":"PPP5C","group":"Protein","label":"PPP5C"},{"id":"CTNNB1","group":"Protein","label":"CTNNB1"},{"id":"KRAS","group":"Protein","label":"KRAS"}]}' ></drugst-one> @@ -171,7 +171,7 @@ Export As Graphml Button<br> } function initTaskEventListener() { - let color1 = '#ff1818' + let color1 = '#c80bfd' document.getElementsByTagName("drugst-one")[0].addEventListener("taskEvent", (event) => { console.log(event.detail) }) @@ -241,6 +241,9 @@ Export As Graphml Button<br> </body> </html> <style> - /*:root {--drgstn-font-family: Oxygen}*/ + :root { + /*--drgstn-panel: #000;*/ + /*--drgstn-text-primary: #fff;*/ + } </style>