Thursday, October 8, 2015

Making Time Based Graphs with Chartist

I have been implementing some custom charts with Chartist recently.  Overall things have gone very well with some simple tweaks and fiddling to get things exactly how I want.  It is very nice to be be able to easily adjust the charts with CSS right in the normal site code.

The only problem I had was using Date based charts that don't have fixed intervals.  If the Dates or Times are at a fixed interval you can just write the values directly to the labels variable and format them how you want very easily.  If you have a random or variable set of dates, say when inventory is logged which is done at a random, there is no easy way to graph this and keep the relative positions correct on the graph.  I don't want all the points one unit apart, as one could be two weeks and the next 2 months, but rather properly positioned based on the date provided.

Anyway, I got it to work and where is a brief example/sample code to try out.
<script src="/scripts/chartist.min.js" type="text/javascript"></script>
<script src="/scripts/chartist-plugin-tooltip.js" type="text/javascript"></script>
<link href="/css/chartist.min.css" type="text/css" rel="stylesheet">
<link href="/css/z-date-time-graph.css" type="text/css" rel="stylesheet">
<div class="item-trend"></div>
<script type="text/javascript">
// This data is output via Mvc/JSON in my case. But it can come from any source, jsut make sure to pass the date/time in as a Date object.
var data = {"transDate":new Date(1393995600000),"inStockCount":95},
{"transDate":new Date(1396152000000),"inStockCount":62},
{"transDate":new Date(1398225600000),"inStockCount":51},
{"transDate":new Date(1400644800000),"inStockCount":35}
];
new Chartist.Line('.item-trend', {
series: [
data.map(function(s) {
// Meta is only needed if using the tooltip plugin.
return {x: s.transDate, y: s.inStockCount, meta: s.inStockCount + ' on ' + s.transDate.toDateString()};
})
]
}, {
// This is making a short trendline type graph. It can be removed to make a full size graph with lavels and grid lines.
chartPadding: 5,
height: '60px',
axisX: {
type: Chartist.AutoScaleAxis,
showGrid: false,
// This is reformats the dates to a nice ledgeble format. The width should be added to ensure that to many items aren't rendered and thus overlap.
scaleMinSpace: 60,
labelInterpolationFnc: function(value, index) {
return (new Date(value)).toLocaleDateString();
},
// These options don't seam to have an effect. As a result the graph won't alwayse be edge to edge as there is some magic formula that desides how to scale the X Axis.
//low: data.transDate.valueOf(),
//high: data[data.length -1].transDate.valueOf()
},
axisY: {
showGrid: false,
// Turning off the units here to make it a smaller trendline.
offset: 0,
labelInterpolationFnc: function(value, index) {
return null;
}
},
plugins: [
// Adding tooltips the the details on hover as they dont display ont he small graph.
Chartist.plugins.tooltip()
]
});
</script>
.item-trend .ct-series line.ct-point {
stroke-width: 5px;
}
.item-trend .ct-series path.ct-line {
stroke-width: 3px;
}
.chartist-tooltip {
position: absolute;
display: inline-block;
min-width: 5em;
padding: .5em;
background: #F4C63D;
color: #453D3F;
font-weight: 700;
text-align: center;
pointer-events: none;
z-index: 1
}
.chartist-tooltip:after {
content: "";
position: absolute;
top: 100%;
left: 50%;
width: 0;
height: 0;
margin-left: -15px;
border: 15px solid transparent;
border-top-color: #F4C63D
}
.chartist-tooltip-value {
display: none;
}

As you can see in the sample here the items are positioned properly.

No comments: