1
0
Fork 0

Add box chart axis

This commit is contained in:
Gregory Eremin 2016-01-10 18:51:43 +03:00
parent f0450ea703
commit ef276ed577
2 changed files with 57 additions and 43 deletions

View File

@ -47,6 +47,7 @@ body {
width: 950px; width: 950px;
height: 120px; height: 120px;
margin-right: 15px; margin-right: 15px;
margin-bottom: 10px;
} }
.linechart svg { .linechart svg {
width: 100%; width: 100%;
@ -69,13 +70,13 @@ body {
.linechart .dot.errors { .linechart .dot.errors {
fill: #f64; fill: #f64;
} }
.linechart .axis { .axis {
stroke: #888; stroke: #888;
} }
.linechart .arrow { .arrow {
stroke: #888; stroke: #888;
fill: #888; fill: #888;
} }
/* /*
@ -85,7 +86,7 @@ body {
.boxplot { .boxplot {
float: left; float: left;
width: 950px; width: 950px;
height: 200px; height: 170px;
} }
.boxplot svg { .boxplot svg {
width: 100%; width: 100%;

View File

@ -97,8 +97,13 @@ var Daemon = React.createClass({
var BoxPlot = React.createClass({ var BoxPlot = React.createClass({
render: function(){ render: function(){
var points = this.props.points, var points = this.props.points,
maxHeight = 140, chartWidth = 950,
padding = 5; chartHeight = 170,
padLeft = 30,
padTop = 10,
padBottom = 20,
valueInterval = 5,
maxHeight = chartHeight - padTop - padBottom;
var min, max; var min, max;
points.map(function(point) { points.map(function(point) {
@ -112,14 +117,13 @@ var BoxPlot = React.createClass({
var renderBox = function(point, i) { var renderBox = function(point, i) {
var relativeY = function(val) { var relativeY = function(val) {
return maxHeight - Math.round((val-min)/(max-min) * maxHeight) + padding; return maxHeight - Math.round((val-min)/(max-min) * maxHeight);
}; };
var width = 10; var boxWidth = 10;
var padding = 5;
var x1 = (width + padding) * i + padding; var x1 = (boxWidth + valueInterval) * i + padLeft + valueInterval;
var x2 = x1 + width; var x2 = x1 + boxWidth;
var minY = relativeY(point.min); var minY = relativeY(point.min);
var p25Y = relativeY(point.p25); var p25Y = relativeY(point.p25);
var medianY = relativeY(point.median); var medianY = relativeY(point.median);
@ -135,21 +139,21 @@ var BoxPlot = React.createClass({
y2={maxY} y2={maxY}
className="tick" /> className="tick" />
<line key="max-whisker" <line key="max-whisker"
x1={x1+width/2} x1={x1+boxWidth/2}
x2={x1+width/2} x2={x1+boxWidth/2}
y1={maxY} y1={maxY}
y2={p75Y} y2={p75Y}
className="whisker" /> className="whisker" />
<line key="min-whisker" <line key="min-whisker"
x1={x1+width/2} x1={x1+boxWidth/2}
x2={x1+width/2} x2={x1+boxWidth/2}
y1={minY} y1={minY}
y2={p25Y} y2={p25Y}
className="whisker" /> className="whisker" />
<rect key="iqr" <rect key="iqr"
x={x1} x={x1}
y={p75Y} y={p75Y}
width={width} width={boxWidth}
height={p25Y - p75Y} height={p25Y - p75Y}
className="iqr" /> className="iqr" />
<line key="median" <line key="median"
@ -167,10 +171,22 @@ var BoxPlot = React.createClass({
</g> </g>
); );
}; };
var yMaxX = padLeft - 3,
yMaxY = padTop + 5;
return ( return (
<div className="boxplot"> <div className="boxplot">
<svg> <svg>
<text key="title" x={-70} y={10} textAnchor="middle" transform="rotate(270)" className="axis-label">Speed</text>
{this.props.points.map(renderBox)} {this.props.points.map(renderBox)}
<line key="y-axis" x1={padLeft} x2={padLeft} y1={0} y2={maxHeight} className="axis" />
<path key="y-arrow" d="M30,0 32,7 28,7 Z" className="arrow" />
<text key="y-max" x={yMaxX} y={yMaxY} textAnchor="end"className="axis-label">{max.toFixed(1)}</text>
<text key="y-zero" x={27} y={100} textAnchor="end" className="axis-label">0</text>
<line key="x-axis" x1={padLeft} x2={950} y1={maxHeight} y2={maxHeight} className="axis" />
<path key="x-arrow" d="M950,140 943,142 943,138 Z" className="arrow" />
<text key="x-label-now" x={940} y={chartHeight - padBottom} textAnchor="end" className="axis-label">now</text>
</svg> </svg>
</div> </div>
); );
@ -179,17 +195,16 @@ var BoxPlot = React.createClass({
var LineChart = React.createClass({ var LineChart = React.createClass({
render: function() { render: function() {
var width = 950,
height = 120,
paddingLeft = 30,
paddingTop = 10,
paddingBottom = 20;
var points = this.props.points, var points = this.props.points,
maxHeight = height - paddingTop - paddingBottom, chartWidth = 950,
padding = 30; chartHeight = 120,
padLeft = 30,
padTop = 10,
padBottom = 20,
valueInterval = 15;
maxHeight = chartHeight - padTop - padBottom;
var min = 0, max = 0; var max = 0;
points.map(function(point) { points.map(function(point) {
if (max === undefined || point.processed > max) { if (max === undefined || point.processed > max) {
max = point.processed; max = point.processed;
@ -203,19 +218,18 @@ var LineChart = React.createClass({
var npoints = points.map(function(point, i) { var npoints = points.map(function(point, i) {
var val = point[key]; var val = point[key];
var width = 15; var x = i * valueInterval + padLeft;
var x = i * width + padding; var y = maxHeight - Math.round(val/max * maxHeight) + padTop;
var y = maxHeight - Math.round((val-min)/(max-min) * maxHeight) + paddingTop;
return [x, y]; return [x, y];
}); });
var numMaxPoints = points.map(function(point, i) { var maxPointsRatio = points.map(function(point, i) {
var val = point[key]; var val = point[key];
return val === max ? 1 : 0; return val === max ? 1 : 0;
}).reduce(function(sum, val) { }).reduce(function(sum, val) {
return sum + val; return sum + val;
}); }) / points.length;
var path = npoints.map(function(point, i) { var path = npoints.map(function(point, i) {
var x = point[0], y = point[1]; var x = point[0], y = point[1];
@ -232,11 +246,11 @@ var LineChart = React.createClass({
var r = 2; // Radius var r = 2; // Radius
// Hide leftmost and zero points // Hide leftmost and zero points
if (x === paddingLeft || y === height - paddingBottom) { if (x === padLeft || y === chartHeight - padBottom) {
r = 0; r = 0;
} }
// Highlight max values if less then 50% of values are max // Highlight max values if less then 25% of values are max
if (y == paddingTop && numMaxPoints / points.length < .5) { if (y == padTop && maxPointsRatio <= .25) {
r = 4; r = 4;
} }
@ -258,14 +272,12 @@ var LineChart = React.createClass({
}; };
// TODO: Define magic numbers from below here // TODO: Define magic numbers from below here
var yMaxX = paddingLeft - 3, var yMaxX = padLeft - 3,
yMaxY = paddingTop + 5, yMaxY = padTop + 5;
xLabel1x = paddingLeft,
xLabel2x = paddingLeft + 15 * 6;
var xlabels = Array.apply(null, Array(10)).map(function(_, i){ var xlabels = Array.apply(null, Array(10)).map(function(_, i){
return <text key={"x-label-"+ i} return <text key={"x-label-"+ i}
x={paddingLeft + (15 * 6 * i)} x={padLeft + (15 * 6 * i)}
y={110} y={110}
textAnchor="middle" textAnchor="middle"
className="axis-label"> className="axis-label">
@ -276,9 +288,10 @@ var LineChart = React.createClass({
return ( return (
<div className="linechart"> <div className="linechart">
<svg> <svg>
<text key="title" x={-50} y={10} textAnchor="middle" transform="rotate(270)" className="axis-label">Throughput</text>
{makePath(points, "processed")} {makePath(points, "processed")}
{makePath(points, "errors")} {makePath(points, "errors")}
<line key="y-axis" x1={30} x2={30} y1={0} y2={100} className="axis" /> <line key="y-axis" x1={padLeft} x2={padLeft} y1={0} y2={100} className="axis" />
<path key="y-arrow" d="M30,0 32,7 28,7 Z" className="arrow" /> <path key="y-arrow" d="M30,0 32,7 28,7 Z" className="arrow" />
<text key="y-max" x={yMaxX} y={yMaxY} textAnchor="end"className="axis-label">{max}</text> <text key="y-max" x={yMaxX} y={yMaxY} textAnchor="end"className="axis-label">{max}</text>
<text key="y-zero" x={27} y={100} textAnchor="end" className="axis-label">0</text> <text key="y-zero" x={27} y={100} textAnchor="end" className="axis-label">0</text>