Preact
by Rishi Kumar
HTML
<div id="app"></div>
CSS
body {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 14px;
}
.LineChart {
position: relative;
padding-left: 40px;
padding-bottom: 40px;
}
svg {
fill: none;
stroke: #33C7FF;
display: block;
stroke-width: 2px;
border-left: 1px solid black;
border-bottom: 1px solid black;
}
.x-axis {
position: absolute;
bottom: 0;
height: 40px;
left: 40px;
right: 0;
display: flex;
justify-content: space-between;
}
.y-axis {
position: absolute;
top: 0;
left: 0;
width: 40px;
bottom: 40px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
}
.y-axis > div::after {
margin-right: 4px;
content: attr(data-value);
color: black;
display: inline-block;
}
.x-axis > div::after {
margin-top: 4px;
display: inline-block;
content: attr(data-value);
color: black;
}
Preact
/* @jsx h */
let { Component, h, render } = preact
function getTicks (count, max) {
return [...Array(count).keys()].map(d => max / (count - 1) * parseInt(d))
}
class LineChart extends Component {
render ({ data }) {
let WIDTH = 500;
let HEIGHT = 300;
let TICK_COUNT = 5;
let MAX_X = Math.max(...data.map(d => d.x));
let MAX_Y = Math.max(...data.map(d => d.y));
let x = val => val / MAX_X * WIDTH;
let y = val => HEIGHT - val / MAX_Y * HEIGHT;
let x_ticks = getTicks(TICK_COUNT, MAX_X);
let y_ticks = getTicks(TICK_COUNT, MAX_Y).reverse();
let d = `M${x(data[0].x)} ${y(data[0].y)} ${data.slice(1).map(d => {
return `L${x(d.x)} ${y(d.y)}`;
}).join(' ')}`;
return (
<div class="LineChart" style={`width: ${WIDTH}px; height: ${HEIGHT}px`}>
<svg width={WIDTH} height={HEIGHT}>
<path d={d} />
</svg>
<div class="x-axis">
{x_ticks.map(v => <div data-value={v} />)}
</div>
<div class="y-axis">
{y_ticks.map(v => <div data-value={v} />)}
</div>
</div>
);
}
}
let data = [
{x: 0, y: 10},
{x: 10, y: 40},
{x: 20, y: 30},
{x: 30, y: 70},
{x: 40, y: 0}
];
render(<LineChart data={data} />, document.querySelector("#app"))