onMouseOut(lockedMetric)}>
{_.map(METRICS, (key, name) => {
return (
onMouseOver(key)}>
+ onMouseOver={() => onMouseOver(key)}
+ onClick={() => onMouseClick(key)}>
{name}
);
diff --git a/client/app/scripts/constants/action-types.js b/client/app/scripts/constants/action-types.js
index 87aac25b9..ab5a20ca2 100644
--- a/client/app/scripts/constants/action-types.js
+++ b/client/app/scripts/constants/action-types.js
@@ -23,6 +23,7 @@ const ACTION_TYPES = [
'ENTER_NODE',
'LEAVE_EDGE',
'LEAVE_NODE',
+ 'LOCK_METRIC',
'OPEN_WEBSOCKET',
'RECEIVE_CONTROL_PIPE',
'RECEIVE_CONTROL_PIPE_STATUS',
diff --git a/client/app/scripts/stores/app-store.js b/client/app/scripts/stores/app-store.js
index 8e3115666..569142208 100644
--- a/client/app/scripts/stores/app-store.js
+++ b/client/app/scripts/stores/app-store.js
@@ -58,7 +58,9 @@ let routeSet = false;
let controlPipes = makeOrderedMap(); // pipeId -> controlPipe
let updatePausedAt = null; // Date
let websocketClosed = true;
+
let selectedMetric = 'process_cpu_usage_percent';
+let lockedMetric = selectedMetric;
const topologySorter = topology => topology.get('rank');
@@ -165,6 +167,10 @@ export class AppStore extends Store {
return adjacentNodes;
}
+ getLockedMetric() {
+ return lockedMetric;
+ }
+
getSelectedMetric() {
return selectedMetric;
}
@@ -411,6 +417,11 @@ export class AppStore extends Store {
this.__emitChange();
break;
}
+ case ActionTypes.LOCK_METRIC: {
+ lockedMetric = payload.metricId;
+ this.__emitChange();
+ break;
+ }
case ActionTypes.DESELECT_NODE: {
closeNodeDetails();
this.__emitChange();
diff --git a/client/app/scripts/utils/data-utils.js b/client/app/scripts/utils/data-utils.js
index d7276ce51..d37d7d399 100644
--- a/client/app/scripts/utils/data-utils.js
+++ b/client/app/scripts/utils/data-utils.js
@@ -1,5 +1,6 @@
import _ from 'lodash';
import d3 from 'd3';
+import { formatMetric } from './string-utils';
// Inspired by Lee Byron's test data generator.
@@ -80,23 +81,19 @@ export function addMetrics(delta, prevNodes) {
export function getMetricValue(metric, size) {
if (!metric) {
- return {height: 0, v: null};
+ return {height: 0, value: null, formattedValue: 'n/a'};
}
const max = metric.getIn(['max']);
- const v = metric.getIn(['samples', 0, 'value']);
- const vp = v === 0 ? 0 : v / max;
+ const value = metric.getIn(['samples', 0, 'value']);
+ const valuePercentage = value === 0 ? 0 : value / max;
const baseline = 0.05;
- const displayedValue = vp * (1 - baseline) + baseline;
+ const displayedValue = valuePercentage * (1 - baseline) + baseline;
const height = size * displayedValue;
- return {height, v};
-}
-
-const formatLargeValue = d3.format('s');
-export function formatCanvasMetric(v) {
- if (v === null) {
- return 'n/a';
- }
- return formatLargeValue(Number(v).toFixed(1));
+ return {
+ height: height,
+ value: value,
+ formattedValue: formatMetric(value, metric.toJS(), true)
+ };
}
diff --git a/client/app/scripts/utils/string-utils.js b/client/app/scripts/utils/string-utils.js
index e4f3b9bdb..40dee2791 100644
--- a/client/app/scripts/utils/string-utils.js
+++ b/client/app/scripts/utils/string-utils.js
@@ -4,43 +4,54 @@ import d3 from 'd3';
const formatLargeValue = d3.format('s');
-const formatters = {
- filesize(value) {
- const obj = filesize(value, {output: 'object'});
- return formatters.metric(obj.value, obj.suffix);
- },
+function toHtml(text, unit) {
+ return (
+
+ {text}
+ {unit}
+
+ );
+}
- integer(value) {
- if (value < 1100 && value >= 0) {
- return Number(value).toFixed(0);
+
+function makeFormatters(renderFn) {
+ const formatters = {
+ filesize(value) {
+ const obj = filesize(value, {output: 'object'});
+ console.log('rendering', value);
+ return renderFn(obj.value, obj.suffix);
+ },
+
+ integer(value) {
+ if (value < 1100 && value >= 0) {
+ return Number(value).toFixed(0);
+ }
+ return formatLargeValue(value);
+ },
+
+ number(value) {
+ if (value < 1100 && value >= 0) {
+ return Number(value).toFixed(2);
+ }
+ return formatLargeValue(value);
+ },
+
+ percent(value) {
+ return renderFn(formatters.number(value), '%');
}
- return formatLargeValue(value);
- },
+ };
- number(value) {
- if (value < 1100 && value >= 0) {
- return Number(value).toFixed(2);
- }
- return formatLargeValue(value);
- },
+ return formatters;
+}
- percent(value) {
- return formatters.metric(formatters.number(value), '%');
- },
- metric(text, unit) {
- return (
-
- {text}
- {unit}
-
- );
- }
-};
+const formatters = makeFormatters(toHtml);
+const svgFormatters = makeFormatters((text, unit) => `${text}${unit}`);
-export function formatMetric(value, opts) {
- const formatter = opts && formatters[opts.format] ? opts.format : 'number';
- return formatters[formatter](value);
+export function formatMetric(value, opts, svg) {
+ const formatterBase = svg ? svgFormatters : formatters;
+ const formatter = opts && formatterBase[opts.format] ? opts.format : 'number';
+ return formatterBase[formatter](value);
}
export const formatDate = d3.time.format.iso;