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"))