var Dashboard = React.createClass({ getInitialState: function() { return {}; }, componentDidMount: function() { this.reload(); }, reload: function() { getURL("http://127.0.0.1:6464/stats.json", {}, function(resp) { if (resp.error !== undefined) { console.log("Stats server is offline"); setTimeout(this.reload, 3000); return } var newState = {}; var decode = function(point) { return { timestamp: point[0], processed: point[1], errors: point[2], min: point[3], p25: point[4], mean: point[5], median: point[6], p75: point[7], max: point[8], } }; var padWithValues = function(points, target) { var pointsToAdd = target - points.length; for (var i = 0; i < pointsToAdd; i++) { points.unshift({ timestamp: 0, processed: 0, errors: 0, min: 0, p25: 0, mean: 0, median: 0, p75: 0, max: 0, }); } return points }; for (name in resp) { newState[name] = resp[name].map(decode); newState[name] = padWithValues(newState[name], 61); } this.setState(newState); setTimeout(this.reload, 3000); }.bind(this)); }, renderDaemons: function() { var daemons = []; for (name in this.state) { daemons.push(); } return daemons; }, render: function() { return (
{this.renderDaemons()}
); } }); var Header = React.createClass({ render: function() { return (
Daemon
Processed
Errors
Min
Median
Max
); } }); var StatsRow = React.createClass({ render: function() { var value = this.props.value; var errorsClasses = ["table-cell", "col-errors"]; if (value.errors > 0) { errorsClasses.push("attn"); } return (
{this.props.name}
{value.processed}
{value.errors}
{formatDuration(value.min)}
{formatDuration(value.median)}
{formatDuration(value.max)}
); } }); var Daemon = React.createClass({ render: function() { var last = this.props.points[this.props.points.length - 1]; return (
); } }); var BoxPlot = React.createClass({ render: function(){ var points = this.props.points, chartWidth = 950, chartHeight = 170, padLeft = 30, padTop = 10, padBottom = 20, valueInterval = 5, maxHeight = chartHeight - padTop - padBottom; // Skipping first point points.shift(); var min, max; points.map(function(point) { if (min === undefined || point.min < min) { min = point.min; } if (max === undefined || point.max > max) { max = point.max; } }); var renderBox = function(point, i) { if (point.max === 0) { return; } var relativeY = function(val) { return maxHeight - Math.round((val-min)/(max-min) * maxHeight); }; var boxWidth = 10; var x1 = (boxWidth + valueInterval)*i + padLeft + 2*valueInterval; var x2 = x1 + boxWidth; var minY = relativeY(point.min); var p25Y = relativeY(point.p25); var medianY = relativeY(point.median); var p75Y = relativeY(point.p75); var maxY = relativeY(point.max); return ( ); }; var yMaxX = padLeft - 3, yMaxY = padTop + 5; var xlabels = Array.apply(null, Array(10)).map(function(_, i){ return {"-"+ (10-i) + "m"} }); return (
Speed {max.toFixed(1)} 0 now {xlabels} {this.props.points.map(renderBox)}
); } }); var LineChart = React.createClass({ render: function() { var points = this.props.points, chartWidth = 950, chartHeight = 120, padLeft = 30, padTop = 10, padBottom = 20, valueInterval = 15; maxHeight = chartHeight - padTop - padBottom; var max = 0; points.map(function(point) { if (max === undefined || point.processed > max) { max = point.processed; } }); var makePath = function(points, key) { if (max === 0) { return; } var npoints = points.map(function(point, i) { var val = point[key]; var x = i * valueInterval + padLeft; var y = maxHeight - Math.round(val/max * maxHeight) + padTop; return [x, y]; }); var maxPointsRatio = points.map(function(point, i) { var val = point[key]; return val === max ? 1 : 0; }).reduce(function(sum, val) { return sum + val; }) / points.length; var path = npoints.map(function(point, i) { var x = point[0], y = point[1]; if (i === 0) { return "M"+x+","+y; } else { return "L"+x+","+y; } }).join(" "); var dots = npoints.map(function(point, i) { var x = point[0], y = point[1]; var r = 2; // Radius // Hide leftmost and zero points if (x === padLeft || y === chartHeight - padBottom) { r = 0; } // Highlight max values if less then 25% of values are max if (y == padTop && maxPointsRatio <= .25) { r = 4; } return }); return ( {dots} ); }; // TODO: Define magic numbers from below here var yMaxX = padLeft - 3, yMaxY = padTop + 5; var xlabels = Array.apply(null, Array(10)).map(function(_, i){ return {"-"+ (10-i) + "m"} }); return (
Throughput {makePath(points, "processed")} {makePath(points, "errors")} {max} 0 now {xlabels}
); } }); ReactDOM.render(, document.getElementById("app"));