JSFiddle - React, Tailwind, and code Playground
by Felis Catus
HTML
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 500">
<defs>
<linearGradient id="graph_fill" x1="0" x2="0" y1="0" y2="1">
<stop class="stop1" offset="0%" stop-color="#00b000" stop-opacity="0.5" />
<stop class="stop2" offset="50%" stop-color="#00b000" stop-opacity="0.1" />
<stop class="stop2" offset="100%" stop-color="#00b000" stop-opacity="0.05" />
</linearGradient>
</defs>
<path id="axes" d="M0,0 v500h1000 M50,0v470h950" stroke="#000000" fill="none" />
<path d="M30,47v-100q3,0 10,0t10,10t10,-50t10,-10t10,-50t10,0V500z" stroke="#b00000" fill="red" fill-opacity="0.0" opacity="0" />
<path id="testpath" d="M0,500v-100c5,0 5,0 10,0s 5,10 10,10s 5,-50 10,-50s5,-10 10,-10s5,-50 10,-50s5,0 10,0V500" stroke="#00b000" fill="url(#graph_fill)" />
<path id="testpath2" d="" stroke="#00b0b0" fill="none" />
<g id="yaxis">
</g>
</svg>
CSS
#yaxis {
font-family: sans-serif;
font-size: 10px;
}
JavaScript
function yscale(max) {
var ret = {};
ret.y = max;
ret.zeroes = Math.floor(Math.log10(max));
ret.top = Math.ceil(max.toString().slice(0, -Math.floor(ret.zeroes - 1)) / 10);
ret.axis_top = ret.top * Math.pow(10, ret.zeroes);
ret.thousands = Math.floor(ret.zeroes / 3);
ret.letter = ['', 'K', 'M', 'G', 'T'][ret.thousands];
ret.factor = Math.pow(10, ret.thousands * 3);
return ret;
}
function compose_graph(datapoints, opt) {
var offset;
return datapoints.reduce(function(path, pt, idx, arr) {
if (idx == 0)
offset = pt[1];
var x = opt.start.x + (pt[1] - offset) * opt.factor.x;
var y = opt.start.y + (pt[0]||0) * opt.factor.y;
path += (idx == 0 ? 'C' + x + ',' + y + ' ' : 'S') + (x - 10) + ',' + y + ' ' + x + ',' + y;
if (idx == arr.length - 1)
path += 'V' + opt.start.y;
return path;
}, 'M' + opt.start.x + ',' + opt.start.y);
}
var svgns = 'http://www.w3.org/2000/svg';
function fill_axes(datapoints, opt) {
var max = datapoints.reduce(function(max, next) {
return Math.max(max, next[0]||0);
}, 1);
var ysc = yscale(max);
console.log('yscale', ysc);
var step = ysc.top <= 2 ? 0.1 : (ysc.top <= 5 ? 0.5 : 1);
var gr = document.querySelector('#yaxis');
gr.innerHTML = '';
for (var y = 0; y <= ysc.top; y += step) {
var tx = document.createElementNS(svgns, 'text');
tx.textContent = (y * Math.pow(10, ysc.zeroes - ysc.thousands * 3)).toFixed(1) + ' ' + ysc.letter + ' -';
tx.setAttribute('x', opt.start.x);
tx.setAttribute('y', opt.start.y + opt.factor.y * y * Math.pow(10, ysc.zeroes));
tx.setAttribute('text-anchor', 'end');
tx.setAttribute('alignment-baseline', 'middle');
gr.appendChild(tx);
}
var xsc = xscale(datapoints[0][1], datapoints.slice(-1)[0][1]);
console.log('xscale', xsc);
var om, od;
for (var x = xsc.start; x <= xsc.to; x += xsc.step) {
var dt = new Date(x * 1000),
label1 = null, label2 = null;
if (xsc.step < 30 * 86400 && (om !=...