Skip to content

Instantly share code, notes, and snippets.

@FrankSpierings
Last active July 31, 2025 10:00
Show Gist options
  • Save FrankSpierings/1c0e46ad37dc9f81897c0e2df054880e to your computer and use it in GitHub Desktop.
Save FrankSpierings/1c0e46ad37dc9f81897c0e2df054880e to your computer and use it in GitHub Desktop.
Some JS line chart example
<!DOCTYPE html>
<html>
<head>
<title>The Love Graph</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
/* Optional: Basic styling for the canvas container */
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
div {
width: 600px; /* Adjust canvas width */
height: 600px; /* Adjust canvas height */
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<div>
<canvas id="myChart"></canvas>
</div>
<script>
const ctx = document.getElementById('myChart');
const range = [-2.5, 2.5]; // Defines the x-axis range for plotting
const size = 4000; // Number of data points for smoother curves
// Generate x-values evenly distributed within the defined range
const x = Array.from({ length: size }, (_, i) => range[0] + i * ((range[1] - range[0]) / (size - 1)));
// Calculate y-values for the upper half of the heart using the formula: y = sqrt(abs(x)) + sqrt(1 - x^2)
const y_upper = x.map(val => {
// Ensure 1 - val*val is not negative to avoid NaN from Math.sqrt()
if (1 - val * val >= 0) {
return Math.sqrt(Math.abs(val)) + Math.sqrt(1 - val * val);
}
return NaN; // Return NaN for values outside the valid domain (e.g., |x| > 1 for sqrt(1-x^2))
});
// Calculate y-values for the lower half of the heart using the formula: y = sqrt(abs(x)) - sqrt(1 - x^2)
const y_lower = x.map(val => {
// Ensure 1 - val*val is not negative
if (1 - val * val >= 0) {
return Math.sqrt(Math.abs(val)) - Math.sqrt(1 - val * val);
}
return NaN; // Return NaN for values outside the valid domain
});
const data = {
labels: x, // x-values will be used for labels (though hidden)
datasets: [{
label: 'Upper Half of Heart', // Label for dataset, hidden by legend: false
data: y_upper,
borderColor: 'red',
backgroundColor: 'rgba(255, 99, 132, 0.2)', // Light red fill (though fill: false)
fill: false, // Do not fill the area under the line
tension: 0 // Set tension to 0 for straight lines between points, ensuring sharp corners and connections
},
{
label: 'Lower Half of Heart', // Label for dataset, hidden by legend: false
data: y_lower,
borderColor: 'red',
backgroundColor: 'rgba(255, 99, 132, 0.2)',
fill: false,
tension: 0 // Set tension to 0
}]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true, // Chart will resize with its container
maintainAspectRatio: false, // Allow independent height/width control
scales: {
x: {
title: {
display: true,
text: 'x values'
},
min: range[0],
max: range[1],
ticks: {
display: false // Hide x-axis labels (numbers)
},
grid: {
drawOnChartArea: false // Hide vertical grid lines (those parallel to y-axis)
}
},
y: {
title: {
display: true,
text: 'y values (Heart Shape)'
},
min: range[0], // Keep min same as x-axis min for symmetric view
max: range[1] + 1, // Set y-axis max to ensure top of heart is visible
}
},
plugins: {
title: {
display: true,
text: 'The Love Graph (Heart Shape)',
font: {
size: 18 // Adjust title font size
}
},
legend: {
display: false // Hide the legend entirely
},
tooltip: { // Enable and configure tooltips
enabled: true,
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
// Format x and y values to 3 decimal places
if (context.parsed.x !== null && context.parsed.y !== null) {
label += `(${context.parsed.x.toFixed(3)}, ${context.parsed.y.toFixed(3)})`;
}
return label;
}
}
}
}
}
};
new Chart(ctx, config);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment