diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js index 59023a745..81eeb5033 100644 --- a/client/app/scripts/charts/node.js +++ b/client/app/scripts/charts/node.js @@ -23,7 +23,7 @@ const Node = React.createClass({ let labelOffsetY = 18; let subLabelOffsetY = 35; const isPseudo = !!this.props.pseudo; - const color = isPseudo ? '' : this.getNodeColor(this.props.rank); + const color = isPseudo ? '' : this.getNodeColor(this.props.rank, this.props.label); const onMouseEnter = this.handleMouseEnter; const onMouseLeave = this.handleMouseLeave; const onMouseClick = this.handleMouseClick; diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index fba553293..954b21c99 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -61,7 +61,7 @@ const NodeDetails = React.createClass({ return this.renderLoading(); } - const nodeColor = this.getNodeColorDark(details.rank); + const nodeColor = this.getNodeColorDark(details.rank, details.label_major); const styles = { controls: { 'backgroundColor': this.brightenColor(nodeColor) diff --git a/client/app/scripts/mixins/node-color-mixin.js b/client/app/scripts/mixins/node-color-mixin.js index 525005d88..3773bc950 100644 --- a/client/app/scripts/mixins/node-color-mixin.js +++ b/client/app/scripts/mixins/node-color-mixin.js @@ -1,25 +1,54 @@ const d3 = require('d3'); -const colors = d3.scale.category20(); const PSEUDO_COLOR = '#b1b1cb'; -let colorIndex = 0; +const hueRange = [20, 330]; // exclude red +const hueScale = d3.scale.linear().range(hueRange); +// map hues to lightness +const lightnessScale = d3.scale.linear().domain(hueRange).range([0.5, 0.7]); +const startLetterRange = 'A'.charCodeAt(); +const endLetterRange = 'Z'.charCodeAt(); +const letterRange = endLetterRange - startLetterRange; + +/** + * Converts a text to a 360 degree value + */ +function text2degree(text) { + const input = text.substr(0, 2).toUpperCase(); + let num = 0; + let charCode; + for (let i = 0; i < input.length; i++) { + charCode = Math.max(Math.min(input[i].charCodeAt(), endLetterRange), startLetterRange); + num += Math.pow(letterRange, input.length - i - 1) * (charCode - startLetterRange); + } + hueScale.domain([0, Math.pow(letterRange, input.length)]); + return hueScale(num); +} + +function colors(text, secondText) { + let hue = text2degree(text); + // skip green and shift to the end of the color wheel + if (hue > 70 && hue < 150) { + hue += 80; + } + const saturation = 0.6; + let lightness = 0.5; + if (secondText) { + // reuse text2degree and feed degree to lightness scale + lightness = lightnessScale(text2degree(secondText)); + } + const color = d3.hsl(hue, saturation, lightness); + return color; +} const NodeColorMixin = { - getNodeColor: function(text) { - colorIndex++; - // skip green and red (index 5-8 in d3.scale.category20) - if (colorIndex > 4 && colorIndex < 9) { - colors('_' + colorIndex); - return this.getNodeColor(text); - } - - return colors(text); + getNodeColor: function(text, secondText) { + return colors(text, secondText); }, - getNodeColorDark: function(text) { + getNodeColorDark: function(text, secondText) { if (text === undefined) { return PSEUDO_COLOR; } - const color = d3.rgb(colors(text)); + const color = d3.rgb(colors(text, secondText)); let hsl = color.hsl(); // ensure darkness