basic line graph with separate datasets
parent
73dafb29b8
commit
ad59270a27
|
@ -4,17 +4,25 @@ function normalize(x, min, max) {
|
|||
return (x - min)/(max - min);
|
||||
}
|
||||
|
||||
function translator(minX, minY, maxX, maxY, width, height, top, left, bottom, right) {
|
||||
return (x, y) => {
|
||||
const normalized = [normalize(x, minX, maxX), normalize(y, minY, maxY)];
|
||||
const dataWidth = width - left - right;
|
||||
const dataHeight = height - top - bottom;
|
||||
console.log('translator',{x, y, minX, maxX, minY, maxY, normalized, dataWidth, dataHeight, top, left, bottom, right});
|
||||
return [normalized[0] * dataWidth + left, (((1 - normalized[1]) * dataHeight) + top)];
|
||||
}
|
||||
}
|
||||
|
||||
function colorFactory(i) {
|
||||
const seed = (140 + i * 46);
|
||||
const hue = seed % 360;
|
||||
return `hsl(${hue}, 60%, 43%)`;
|
||||
}
|
||||
|
||||
class Graph {
|
||||
view(vnode) {
|
||||
const { title, width, height, margins, origin, maximums, data } = {...Graph.defaults, ...vnode.attrs};
|
||||
|
||||
const tx = (x, y) => {
|
||||
const normalized = [normalize(x, origin[0], maximums[0]), normalize(y, origin[1], maximums[1])];
|
||||
const dataWidth = width - margins[1] - margins[3];
|
||||
const dataHeight = height - margins[0] - margins[2];
|
||||
console.log('tx',{x,y, normalized});
|
||||
return [normalized[0] * dataWidth + margins[3], ((1-normalized[1]) * dataHeight) + margins[0]];
|
||||
}
|
||||
const { title, width, height, margins, datasets} = {...Graph.defaults, ...vnode.attrs};
|
||||
|
||||
return (
|
||||
<div class="Graph-container">
|
||||
|
@ -27,11 +35,23 @@ class Graph {
|
|||
{ /* Left margin */ }
|
||||
<line x1={margins[3]} y1={margins[0]} x2={margins[3]} y2={height-margins[2]} stroke="#000" stroke-width=".1" />
|
||||
|
||||
{data.map((datum, i) => {
|
||||
const translated = tx(datum[0],datum[1]);
|
||||
const [x, y] = tx(...datum);
|
||||
console.log({translated, datum});
|
||||
return (<circle cx={x} cy={y} r=".5" fill="#000" />)
|
||||
{datasets.map((userProps, i) => {
|
||||
const props = {...Graph.datasetDefaults, ...userProps};
|
||||
const title = props.title ? props.title : `Dataset ${i}`;
|
||||
const color = props.color ? props.color : colorFactory(i);
|
||||
if (props.data.length == 0) return;
|
||||
const hasX = props.data[0].length > 1;
|
||||
const minX = props.minX ?? 0;
|
||||
const maxX = props.maxX ?? hasX ? props.data.reduce((p,c) => Math.max(p, c[0]), 0) : props.data.length;
|
||||
const minY = props.minY ?? 0;
|
||||
const maxY = props.maxY ?? props.data.reduce((prev, current) => Math.max(prev, hasX ? current[1] : current[0]), 0);
|
||||
const tx = translator(minX, minY, maxX, maxY, width, height, ...margins);
|
||||
|
||||
const points = props.data.map((datum) => tx(...datum));
|
||||
const line = (<polyline fill="none" stroke={color} stroke-width=".1" points={points.map((v) => v.join(',')).join(' ')} />)
|
||||
return [line, ...points.map(([x,y]) => (<circle cx={x} cy={y} r=".5" fill={color} />))]
|
||||
|
||||
|
||||
})}
|
||||
</svg>
|
||||
</div>
|
||||
|
@ -43,9 +63,15 @@ Graph.defaults = {
|
|||
width: 100,
|
||||
height: 40,
|
||||
margins: [5, 3, 2, 3], // top right bottom left
|
||||
origin: [0, 0],
|
||||
maximums: [100, 100],
|
||||
data: [[0,0], [100,0], [100, 100], [0, 100], [25,60]],
|
||||
datasets: [],
|
||||
}
|
||||
Graph.datasetDefaults = {
|
||||
title: null,
|
||||
minY: null,
|
||||
maxY: null,
|
||||
minX: null,
|
||||
maxX: null,
|
||||
data: [],
|
||||
}
|
||||
|
||||
export default Graph;
|
|
@ -0,0 +1,44 @@
|
|||
import m from 'mithril';
|
||||
import Layout from '../components/Layout';
|
||||
import Graph from '../components/Graph';
|
||||
|
||||
|
||||
|
||||
const datasets = [
|
||||
{
|
||||
title: "Foo",
|
||||
data: [
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[2, 4],
|
||||
[3, 5],
|
||||
[4, 4],
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Bar",
|
||||
data: [
|
||||
[0, 2],
|
||||
[1, 3],
|
||||
[2, 10],
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Sin',
|
||||
data: [...Array(100).keys()].map((i) => [i/10, Math.sin(i/10)+1]),
|
||||
}
|
||||
]
|
||||
|
||||
class HistoryView {
|
||||
view() {
|
||||
const title = 'Recent Conditions';
|
||||
return (
|
||||
<Layout>
|
||||
<h1 class="title">{title}</h1>
|
||||
<Graph title={title} datasets={datasets} />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default HistoryView;
|
Loading…
Reference in New Issue