diff --git a/client/app/scripts/charts/node-shape-circle.js b/client/app/scripts/charts/node-shape-circle.js
deleted file mode 100644
index 8e034c734..000000000
--- a/client/app/scripts/charts/node-shape-circle.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-import classNames from 'classnames';
-
-import {
- getMetricValue,
- getMetricColor,
- getClipPathDefinition,
- renderMetricValue,
-} from '../utils/metric-utils';
-import {
- NODE_SHAPE_HIGHLIGHT_RADIUS,
- NODE_SHAPE_BORDER_RADIUS,
- NODE_SHAPE_SHADOW_RADIUS,
-} from '../constants/styles';
-
-
-export default function NodeShapeCircle({ id, highlighted, color, metric }) {
- const { height, hasMetric, formattedValue } = getMetricValue(metric);
- const metricStyle = { fill: getMetricColor(metric) };
-
- const className = classNames('shape', 'shape-circle', { metrics: hasMetric });
- const clipId = `mask-${id}`;
-
- return (
-
- {hasMetric && getClipPathDefinition(clipId, height)}
- {highlighted && }
-
-
- {hasMetric && }
- {renderMetricValue(formattedValue, highlighted && hasMetric)}
-
- );
-}
diff --git a/client/app/scripts/charts/node-shape-cloud.js b/client/app/scripts/charts/node-shape-cloud.js
deleted file mode 100644
index 0b2efdffb..000000000
--- a/client/app/scripts/charts/node-shape-cloud.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import {
- NODE_SHAPE_HIGHLIGHT_RADIUS,
- NODE_SHAPE_BORDER_RADIUS,
- NODE_SHAPE_SHADOW_RADIUS,
- NODE_SHAPE_DOT_RADIUS,
- NODE_BASE_SIZE,
-} from '../constants/styles';
-
-// This path is already normalized so no dynamic rescaling is needed.
-const CLOUD_PATH = 'M-125 23.333Q-125 44.036-110.352 58.685-95.703 73.333-75 73.333H66.667Q90.755 '
- + '73.333 107.878 56.211 125 39.089 125 15 125-2.188 115.755-16.445 106.51-30.703 91.406-37.734q'
- + '0.26-3.646 0.261-5.599 0-27.604-19.532-47.136-19.531-19.531-47.135-19.531-20.573 0-37.305 '
- + '11.458-16.732 11.458-24.414 29.948-9.115-8.073-21.614-8.073-13.802 0-23.568 9.766-9.766 9.766-'
- + '9.766 23.568 0 9.766 5.339 17.968-16.797 3.906-27.735 17.513-10.938 13.607-10.937 31.185z';
-
-export default function NodeShapeCloud({ highlighted, color }) {
- const pathProps = r => ({ d: CLOUD_PATH, transform: `scale(${r / NODE_BASE_SIZE})` });
-
- return (
-
- {highlighted && }
-
-
-
-
- );
-}
diff --git a/client/app/scripts/charts/node-shape-heptagon.js b/client/app/scripts/charts/node-shape-heptagon.js
deleted file mode 100644
index 074fbc3e3..000000000
--- a/client/app/scripts/charts/node-shape-heptagon.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import classNames from 'classnames';
-
-import { nodeShapePolygon } from '../utils/node-shape-utils';
-import {
- getMetricValue,
- getMetricColor,
- getClipPathDefinition,
- renderMetricValue,
-} from '../utils/metric-utils';
-import {
- NODE_SHAPE_HIGHLIGHT_RADIUS,
- NODE_SHAPE_BORDER_RADIUS,
- NODE_SHAPE_SHADOW_RADIUS,
-} from '../constants/styles';
-
-
-export default function NodeShapeHeptagon({ id, highlighted, color, metric }) {
- const { height, hasMetric, formattedValue } = getMetricValue(metric);
- const metricStyle = { fill: getMetricColor(metric) };
-
- const className = classNames('shape', 'shape-heptagon', { metrics: hasMetric });
- const pathProps = r => ({ d: nodeShapePolygon(r, 7) });
- const clipId = `mask-${id}`;
-
- return (
-
- {hasMetric && getClipPathDefinition(clipId, height)}
- {highlighted && }
-
-
- {hasMetric && }
- {renderMetricValue(formattedValue, highlighted && hasMetric)}
-
- );
-}
diff --git a/client/app/scripts/charts/node-shape-hexagon.js b/client/app/scripts/charts/node-shape-hexagon.js
deleted file mode 100644
index 511f103ae..000000000
--- a/client/app/scripts/charts/node-shape-hexagon.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import classNames from 'classnames';
-
-import { nodeShapePolygon } from '../utils/node-shape-utils';
-import {
- getMetricValue,
- getMetricColor,
- getClipPathDefinition,
- renderMetricValue,
-} from '../utils/metric-utils';
-import {
- NODE_SHAPE_HIGHLIGHT_RADIUS,
- NODE_SHAPE_BORDER_RADIUS,
- NODE_SHAPE_SHADOW_RADIUS,
-} from '../constants/styles';
-
-
-export default function NodeShapeHexagon({ id, highlighted, color, metric }) {
- const { height, hasMetric, formattedValue } = getMetricValue(metric);
- const metricStyle = { fill: getMetricColor(metric) };
-
- const className = classNames('shape', 'shape-hexagon', { metrics: hasMetric });
- const pathProps = r => ({ d: nodeShapePolygon(r, 6) });
- const clipId = `mask-${id}`;
-
- return (
-
- {hasMetric && getClipPathDefinition(clipId, height)}
- {highlighted && }
-
-
- {hasMetric && }
- {renderMetricValue(formattedValue, highlighted && hasMetric)}
-
- );
-}
diff --git a/client/app/scripts/charts/node-shape-rounded-square.js b/client/app/scripts/charts/node-shape-rounded-square.js
deleted file mode 100644
index dbbe4da81..000000000
--- a/client/app/scripts/charts/node-shape-rounded-square.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import NodeShapeSquare from './node-shape-square';
-
-// TODO how to express a cmp in terms of another cmp? (Rather than a sub-cmp as here).
-// HOC!
-
-export default function NodeShapeRoundedSquare(props) {
- return (
-
- );
-}
diff --git a/client/app/scripts/charts/node-shape-square.js b/client/app/scripts/charts/node-shape-square.js
deleted file mode 100644
index 1400487ea..000000000
--- a/client/app/scripts/charts/node-shape-square.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from 'react';
-import classNames from 'classnames';
-
-import {
- getMetricValue,
- getMetricColor,
- getClipPathDefinition,
- renderMetricValue,
-} from '../utils/metric-utils';
-import {
- NODE_SHAPE_HIGHLIGHT_RADIUS,
- NODE_SHAPE_BORDER_RADIUS,
- NODE_SHAPE_SHADOW_RADIUS,
-} from '../constants/styles';
-
-
-export default function NodeShapeSquare({ id, highlighted, color, rx = 0, ry = 0, metric }) {
- const { height, hasMetric, formattedValue } = getMetricValue(metric);
- const metricStyle = { fill: getMetricColor(metric) };
-
- const className = classNames('shape', 'shape-square', { metrics: hasMetric });
- const rectProps = (scale, borderRadiusAdjustmentFactor = 1) => ({
- width: scale * 2,
- height: scale * 2,
- rx: scale * rx * borderRadiusAdjustmentFactor,
- ry: scale * ry * borderRadiusAdjustmentFactor,
- x: -scale,
- y: -scale
- });
- const clipId = `mask-${id}`;
-
- return (
-
- {hasMetric && getClipPathDefinition(clipId, height)}
- {highlighted && }
-
-
- {hasMetric && }
- {renderMetricValue(formattedValue, highlighted && hasMetric)}
-
- );
-}
diff --git a/client/app/scripts/charts/node-shape-stack.js b/client/app/scripts/charts/node-shape-stack.js
index f49e6cb40..48de1d6b9 100644
--- a/client/app/scripts/charts/node-shape-stack.js
+++ b/client/app/scripts/charts/node-shape-stack.js
@@ -2,6 +2,7 @@ import React from 'react';
import { NODE_BASE_SIZE } from '../constants/styles';
+
export default function NodeShapeStack(props) {
const shift = props.contrastMode ? 0.15 : 0.1;
const highlightScale = [1, 1 + shift];
diff --git a/client/app/scripts/charts/node-shapes.js b/client/app/scripts/charts/node-shapes.js
new file mode 100644
index 000000000..1e39d4f86
--- /dev/null
+++ b/client/app/scripts/charts/node-shapes.js
@@ -0,0 +1,71 @@
+import React from 'react';
+import classNames from 'classnames';
+
+import { NODE_BASE_SIZE } from '../constants/styles';
+import {
+ getMetricValue,
+ getMetricColor,
+ getClipPathDefinition,
+} from '../utils/metric-utils';
+import {
+ pathElement,
+ circleElement,
+ rectangleElement,
+ cloudShapeProps,
+ circleShapeProps,
+ squareShapeProps,
+ hexagonShapeProps,
+ heptagonShapeProps,
+} from '../utils/node-shape-utils';
+
+
+function NodeShape(shapeType, shapeElement, shapeProps, { id, highlighted, color, metric }) {
+ const { height, hasMetric, formattedValue } = getMetricValue(metric);
+ const className = classNames('shape', `shape-${shapeType}`, { metrics: hasMetric });
+ const metricStyle = { fill: getMetricColor(metric) };
+ const clipId = `metric-clip-${id}`;
+
+ return (
+
+ {highlighted && shapeElement({
+ className: 'highlight',
+ transform: `scale(${NODE_BASE_SIZE * 0.7})`,
+ ...shapeProps,
+ })}
+ {shapeElement({
+ className: 'background',
+ transform: `scale(${NODE_BASE_SIZE * 0.48})`,
+ ...shapeProps,
+ })}
+ {hasMetric && getClipPathDefinition(clipId, height, 0.48)}
+ {hasMetric && shapeElement({
+ className: 'metric-fill',
+ transform: `scale(${NODE_BASE_SIZE * 0.48})`,
+ clipPath: `url(#${clipId})`,
+ style: metricStyle,
+ ...shapeProps,
+ })}
+ {shapeElement({
+ className: 'shadow',
+ transform: `scale(${NODE_BASE_SIZE * 0.49})`,
+ ...shapeProps,
+ })}
+ {shapeElement({
+ className: 'border',
+ transform: `scale(${NODE_BASE_SIZE * 0.5})`,
+ stroke: color,
+ ...shapeProps,
+ })}
+ {hasMetric && highlighted ?
+ {formattedValue} :
+
+ }
+
+ );
+}
+
+export const NodeShapeCloud = props => NodeShape('cloud', pathElement, cloudShapeProps, props);
+export const NodeShapeCircle = props => NodeShape('circle', circleElement, circleShapeProps, props);
+export const NodeShapeHexagon = props => NodeShape('hexagon', pathElement, hexagonShapeProps, props);
+export const NodeShapeHeptagon = props => NodeShape('heptagon', pathElement, heptagonShapeProps, props);
+export const NodeShapeSquare = props => NodeShape('square', rectangleElement, squareShapeProps, props);
diff --git a/client/app/scripts/charts/node.js b/client/app/scripts/charts/node.js
index 84f3866de..41c4cc36d 100644
--- a/client/app/scripts/charts/node.js
+++ b/client/app/scripts/charts/node.js
@@ -9,13 +9,15 @@ import MatchedText from '../components/matched-text';
import MatchedResults from '../components/matched-results';
import { NODE_BASE_SIZE } from '../constants/styles';
-import NodeShapeCircle from './node-shape-circle';
import NodeShapeStack from './node-shape-stack';
-import NodeShapeRoundedSquare from './node-shape-rounded-square';
-import NodeShapeHexagon from './node-shape-hexagon';
-import NodeShapeHeptagon from './node-shape-heptagon';
-import NodeShapeCloud from './node-shape-cloud';
import NodeNetworksOverlay from './node-networks-overlay';
+import {
+ NodeShapeCloud,
+ NodeShapeCircle,
+ NodeShapeSquare,
+ NodeShapeHexagon,
+ NodeShapeHeptagon,
+} from './node-shapes';
const labelWidth = 1.2 * NODE_BASE_SIZE;
@@ -23,8 +25,8 @@ const nodeShapes = {
circle: NodeShapeCircle,
hexagon: NodeShapeHexagon,
heptagon: NodeShapeHeptagon,
- square: NodeShapeRoundedSquare,
- cloud: NodeShapeCloud
+ square: NodeShapeSquare,
+ cloud: NodeShapeCloud,
};
function stackedShape(Shape) {
diff --git a/client/app/scripts/constants/styles.js b/client/app/scripts/constants/styles.js
index e952a32eb..53d951037 100644
--- a/client/app/scripts/constants/styles.js
+++ b/client/app/scripts/constants/styles.js
@@ -17,10 +17,11 @@ export const RESOURCES_LABEL_MIN_SIZE = 50;
export const RESOURCES_LABEL_PADDING = 10;
// Node shapes
-export const NODE_SHAPE_HIGHLIGHT_RADIUS = 70;
-export const NODE_SHAPE_BORDER_RADIUS = 50;
-export const NODE_SHAPE_SHADOW_RADIUS = 45;
-export const NODE_SHAPE_DOT_RADIUS = 10;
+export const UNIT_CLOUD_PATH = 'M-1.25 0.233Q-1.25 0.44-1.104 0.587-0.957 0.733-0.75 0.733H0.667Q'
+ + '0.908 0.733 1.079 0.562 1.25 0.391 1.25 0.15 1.25-0.022 1.158-0.164 1.065-0.307 0.914-0.377q'
+ + '0.003-0.036 0.003-0.056 0-0.276-0.196-0.472-0.195-0.195-0.471-0.195-0.206 0-0.373 0.115-0.167'
+ + ' 0.115-0.244 0.299-0.091-0.081-0.216-0.081-0.138 0-0.236 0.098-0.098 0.098-0.098 0.236 0 0.098'
+ + ' 0.054 0.179-0.168 0.039-0.278 0.175-0.109 0.136-0.109 0.312z';
// NOTE: This value represents the node unit radius (in pixels). Since zooming is
// controlled at the top level now, this renormalization would be obsolete (i.e.
// value 1 could be used instead), if it wasn't for the following factors:
diff --git a/client/app/scripts/utils/metric-utils.js b/client/app/scripts/utils/metric-utils.js
index e67852a3f..69edfedd0 100644
--- a/client/app/scripts/utils/metric-utils.js
+++ b/client/app/scripts/utils/metric-utils.js
@@ -2,24 +2,20 @@ import { includes } from 'lodash';
import { scaleLog } from 'd3-scale';
import React from 'react';
-import { NODE_BASE_SIZE, NODE_SHAPE_DOT_RADIUS } from '../constants/styles';
import { formatMetricSvg } from './string-utils';
import { colors } from './color-utils';
-export function getClipPathDefinition(clipId, height) {
+export function getClipPathDefinition(clipId, height, radius) {
+ const barHeight = 1 - (2 * height); // in the interval [-1, 1]
return (
-
-
+
+
);
}
-export function renderMetricValue(value, condition) {
- return condition ? {value} : ;
-}
-
//
// loadScale(1) == 0.5; E.g. a nicely balanced system :).
const loadScale = scaleLog().domain([0.01, 100]).range([0, 1]);
diff --git a/client/app/scripts/utils/node-shape-utils.js b/client/app/scripts/utils/node-shape-utils.js
index 45dbf6b2b..20b59f755 100644
--- a/client/app/scripts/utils/node-shape-utils.js
+++ b/client/app/scripts/utils/node-shape-utils.js
@@ -1,12 +1,27 @@
-import { line, curveCardinalClosed } from 'd3-shape';
+import React from 'react';
import range from 'lodash/range';
+import { line, curveCardinalClosed } from 'd3-shape';
-const shapeSpline = line().curve(curveCardinalClosed.tension(0.65));
+import { UNIT_CLOUD_PATH } from '../constants/styles';
-export function nodeShapePolygon(radius, n) {
+
+export const pathElement = React.createFactory('path');
+export const circleElement = React.createFactory('circle');
+export const rectangleElement = React.createFactory('rect');
+
+function curvedUnitPolygonPath(n) {
+ const curve = curveCardinalClosed.tension(0.65);
+ const spline = line().curve(curve);
const innerAngle = (2 * Math.PI) / n;
- return shapeSpline(range(0, n).map(k => [
- radius * Math.sin(k * innerAngle),
- -radius * Math.cos(k * innerAngle)
+
+ return spline(range(0, n).map(k => [
+ Math.sin(k * innerAngle),
+ -Math.cos(k * innerAngle),
]));
}
+
+export const squareShapeProps = { width: 1.8, height: 1.8, rx: 0.4, ry: 0.4, x: -0.9, y: -0.9 };
+export const heptagonShapeProps = { d: curvedUnitPolygonPath(7) };
+export const hexagonShapeProps = { d: curvedUnitPolygonPath(6) };
+export const cloudShapeProps = { d: UNIT_CLOUD_PATH };
+export const circleShapeProps = { r: 1 };
diff --git a/client/app/styles/_base.scss b/client/app/styles/_base.scss
index cdedc17ff..d2e860236 100644
--- a/client/app/styles/_base.scss
+++ b/client/app/styles/_base.scss
@@ -424,7 +424,7 @@
}
}
- .stack .shape .highlighted {
+ .stack .shape .highlight {
display: none;
}
@@ -432,7 +432,7 @@
.border { display: none; }
.shadow { display: none; }
.node { display: none; }
- .highlighted { display: inline; }
+ .highlight { display: inline; }
}
.stack .shape .metric-fill {
@@ -443,16 +443,17 @@
transform: scale(1);
cursor: pointer;
- .border {
- stroke-width: $node-border-stroke-width;
- fill: $background-color;
- transition: stroke-opacity 0.333s $base-ease, fill 0.333s $base-ease;
- stroke-opacity: 1;
+ .highlight {
+ fill: $weave-blue;
+ fill-opacity: $node-highlight-fill-opacity;
+ stroke: $weave-blue;
+ stroke-width: $node-highlight-stroke-width;
+ stroke-opacity: $node-highlight-stroke-opacity;
}
- &.metrics .border {
+ .background {
+ stroke: none;
fill: $background-lighter-color;
- stroke-opacity: 0.3;
}
.metric-fill {
@@ -461,9 +462,21 @@
fill-opacity: 0.7;
}
+ .border {
+ fill: none;
+ stroke-opacity: 1;
+ stroke-width: $node-border-stroke-width;
+ transition: stroke-opacity 0.333s $base-ease, fill 0.333s $base-ease;
+ }
+
+ &.metrics .border {
+ stroke-opacity: 0.3;
+ }
+
.shadow {
- stroke: none;
- fill: $background-lighter-color;
+ fill: none;
+ stroke: $background-color;
+ stroke-width: $node-shadow-stroke-width;
}
.node {
@@ -478,14 +491,6 @@
dominant-baseline: middle;
text-anchor: middle;
}
-
- .highlighted {
- fill: $weave-blue;
- fill-opacity: $node-highlight-fill-opacity;
- stroke: $weave-blue;
- stroke-width: $node-highlight-stroke-width;
- stroke-opacity: $node-highlight-stroke-opacity;
- }
}
.stack .shape .border {
diff --git a/client/app/styles/_contrast-overrides.scss b/client/app/styles/_contrast-overrides.scss
index f957a2604..4860c5a5f 100644
--- a/client/app/styles/_contrast-overrides.scss
+++ b/client/app/styles/_contrast-overrides.scss
@@ -14,8 +14,9 @@ $edge-color: black;
$node-highlight-fill-opacity: 0.3;
$node-highlight-stroke-opacity: 0.5;
-$node-highlight-stroke-width: 8;
-$node-border-stroke-width: 10;
+$node-highlight-stroke-width: 0.16;
+$node-border-stroke-width: 0.2;
+$node-shadow-stroke-width: 0.25;
$node-pseudo-opacity: 1;
$edge-highlight-opacity: 0.3;
$edge-opacity-blurred: 0;
diff --git a/client/app/styles/_variables.scss b/client/app/styles/_variables.scss
index 91ced8c55..2a9f759dc 100644
--- a/client/app/styles/_variables.scss
+++ b/client/app/styles/_variables.scss
@@ -32,8 +32,9 @@ $terminal-header-height: 44px;
$node-highlight-fill-opacity: 0.1;
$node-highlight-stroke-opacity: 0.4;
-$node-highlight-stroke-width: 2;
-$node-border-stroke-width: 6;
+$node-highlight-stroke-width: 0.04;
+$node-border-stroke-width: 0.12;
+$node-shadow-stroke-width: 0.18;
$node-pseudo-opacity: 0.8;
$node-text-scale: 2;
$edge-highlight-opacity: 0.1;