I make charts for a living thing, and also for fun. I build dashboards at my day job. I also help my friend’s bakery show daily orders on their site. So yeah, I spend time with charts. A lot.
If you’re hunting for more field notes, I recently tried a bunch of open-source JavaScript chart tools and wrote up everything that surprised me along the way.
Over the past year, I used Chart.js, D3.js, Apache ECharts, uPlot, Vega-Lite, Plotly.js, plus a bit of Recharts and Nivo in React projects. I’ll share what felt good, what made me grumpy, and real bits of code I wrote.
Quick note: I ran most tests on a MacBook Air M2 with Vite and TypeScript. But I also tried plain HTML when the use case was tiny. Coffee nearby, always.
What I Reached For, And Why
- Chart.js: Straightforward bar, line, doughnut. Good docs. Good defaults.
- D3.js: Full control for custom visuals. More work. Worth it when you need shapes or odd charts.
- Apache ECharts: Fancy and glossy. Lots of chart types. Good for exec dashboards.
- uPlot: Very fast line charts. Great for live data and lots of points.
- Vega-Lite: You write a spec. It builds the chart. Great for quick reports.
- Plotly.js: Built-in zoom, pan, and save to PNG. Nice for analysis.
- Recharts / Nivo: If you’re in React, these save time. Open source too.
For a broader sweep of the landscape, here’s how it went when I tried 7 JavaScript chart libraries back-to-back in one weekend.
Honestly, I bounce between them. Like picking shoes. Depends on the day and the walk.
Real Projects I Shipped
1) Sales Dashboard at Work (Chart.js)
We needed a weekly sales view with targets. Nothing fancy, but it had to look clean in a slide deck. I used Chart.js with the annotation plugin for a target line. It took me one lunch break.
Small example I wrote for a line chart:
<canvas id="salesChart"></canvas>
<script type="module">
import { Chart } from 'chart.js/auto';
import annotationPlugin from 'chartjs-plugin-annotation';
Chart.register(annotationPlugin);
const ctx = document.getElementById('salesChart');
new Chart(ctx, {
type: 'line',
data: {
labels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
datasets: [{
label: 'Sales',
data: [120, 150, 180, 130, 170, 190, 210],
borderColor: '#4f46e5',
tension: 0.3,
fill: false
}]
},
options: {
plugins: {
annotation: {
annotations: {
target: {
type: 'line',
yMin: 160, yMax: 160,
borderColor: '#ef4444',
borderWidth: 2,
label: { display: true, content: 'Target' }
}
}
}
}
}
});
</script>
Good: Fast to set up, looks tidy, colors behave.
Bad: Legends and labels can get cramped on small screens. Also, pie labels still bug me. I had to use a plugin for nice outside labels. If doughnut charts are on your mind, you might like seeing how I built 5 JavaScript donut charts and compared the quirks side by side.
2) Greenhouse Sensors, Live (uPlot)
My neighbor runs a small greenhouse. We stream temperature and humidity over WebSocket. With uPlot, the chart stayed smooth even with 50,000+ points. I tested updates at 1 second. It barely blinked.
Tiny setup I used:
<div id="u"></div>
<script type="module">
import uPlot from "uplot";
import "uplot/dist/uPlot.min.css";
const data = [
[], // x
[], // temp
];
const u = new uPlot({
width: 600,
height: 300,
series: [
{},
{ label: "Temp (°C)", stroke: "tomato" }
],
axes: [
{ grid: { show: true } },
{ grid: { show: true } }
],
}, data, document.getElementById("u"));
// pretend stream
let x = 0;
setInterval(() => {
data[0].push(x++);
data[1].push(20 + Math.sin(x/10) * 3);
u.setData(data);
}, 1000);
</script>
Good: Tiny size and fast.
Bad: Docs are short. You’ll poke around a bit. But once it clicks, it flies.
If you’re looking at live feeds for trading dashboards, I wrote up what worked (and what crashed) when I built a tiny trading dashboard with real-time price data.
3) Beautiful Executive View (Apache ECharts)
I built a quarterly “wins and trends” screen for leadership. ECharts gave me tooltips, gradients, and smooth transitions right away. I used a theme and a bar-with-line overlay. The wow factor helped the story.
Good: Looks rich without much effort. Loads of chart types.
Bad: Bigger bundle. If your app is tight on size, you’ll notice.
4) Weird Shape, Full Control (D3.js)
A product manager wanted a custom “bump chart” with labels that dodge each other. D3 saved me. I wrote scales, axes, and little label rules. It took a weekend, plus a rainy Sunday. But the result? Chef’s kiss.
Here’s a tiny D3 bit I used to make a simple bar:
<svg id="chart" width="400" height="200"></svg>
<script type="module">
import * as d3 from "d3";
const data = [5, 8, 3, 10, 6];
const svg = d3.select("#chart");
const x = d3.scaleBand().domain(d3.range(data.length)).range([0, 400]).padding(0.2);
const y = d3.scaleLinear().domain([0, d3.max(data)]).range([200, 0]);
svg.selectAll("rect")
.data(data)
.join("rect")
.attr("x", (_, i) => x(i))
.attr("y", d => y(d))
.attr("width", x.bandwidth())
.attr("height", d => 200 - y(d))
.attr("fill", "#10b981");
</script>
Good: You can make anything.
Bad: Time. Also, you need to manage labels, legends, colors, and a11y yourself. For a deeper dive into life with SVG and data joins, here’s what happened when I built charts with D3.js for a production feature.
5) Quick Classroom Report (Vega-Lite)
For my cousin’s science fair, we charted plant growth by day. I wrote a small Vega-Lite spec and used vega-embed. We tweaked colors, added a title, and printed it. We even set alt text and a caption.
Good: Fast from idea to chart. Clear JSON spec.
Bad: Styling outside the spec can feel funky.
6) Ad-Hoc Data Story (Plotly.js)
I had to show distribution and let folks zoom in. Plotly gave me histograms with zoom and a “save as PNG” button. No plugin hunt. It made stakeholder calls easier because they could poke at the data.
Good: Interactions out of the box.
Bad: Size is on the heavy side. And theming can feel different from your app style.
If your next report leans toward timelines and dependencies, you might enjoy my notes on how I tried free Gantt chart JavaScript libraries so you don’t have to wrestle each one yourself.
Side note: last month I helped a researcher visualize spikes in ephemeral photo-sharing among teens. Before we touched the data, we grounded ourselves in the topic by reading an eye-opening primer on snap-based sexting — Snap Sexting — which explains the term, the privacy risks, and the shifting cultural norms, giving you crucial context before you start charting that kind of behavior.
In a similar vein of location-specific, user-generated datasets
