function renderFertilityCurve() {
const canvas = document.getElementById('fertilityCurve');
const ctx = canvas.getContext('2d');
const w = canvas.width, h = canvas.height;
ctx.clearRect(0, 0, w, h);
const days = [-5,-4,-3,-2,-1,0,1,2,3,4,5];
const probs = [15,25,40,60,85,95,85,60,30,15,5];
const padding = 40;
const chartW = w - padding * 2;
const chartH = h - padding * 2;
ctx.strokeStyle = '#e8e4df'; ctx.lineWidth = 1;
for (let i = 0; i <= 5; i++) {
const y = padding + (chartH / 5) * i;
ctx.beginPath(); ctx.moveTo(padding, y); ctx.lineTo(w - padding, y); ctx.stroke();
}
ctx.strokeStyle = '#e85a8a'; ctx.lineWidth = 3; ctx.beginPath();
days.forEach((d, i) => {
const x = padding + (chartW / (days.length - 1)) * i;
const y = padding + chartH - (probs[i] / 100) * chartH;
if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
});
ctx.stroke();
ctx.fillStyle = '#e85a8a';
days.forEach((d, i) => {
const x = padding + (chartW / (days.length - 1)) * i;
const y = padding + chartH - (probs[i] / 100) * chartH;
ctx.beginPath(); ctx.arc(x, y, 5, 0, Math.PI * 2); ctx.fill();
});
ctx.fillStyle = '#8a8a8a'; ctx.font = '12px Segoe UI'; ctx.textAlign = 'center';
days.forEach((d, i) => {
const x = padding + (chartW / (days.length - 1)) * i;
ctx.fillText((d > 0 ? '+' : '') + d + 'd', x, h - 15);
});
}
// Init chart
renderFertilityCurve();
function renderFertilityCurve() {
const canvas = document.getElementById('fertilityCurve');
const ctx = canvas.getContext('2d');
const w = canvas.width, h = canvas.height;
ctx.clearRect(0, 0, w, h);
const days = [-5,-4,-3,-2,-1,0,1,2,3,4,5];
const probs = [15,25,40,60,85,95,85,60,30,15,5];
const padding = 40;
const chartW = w - padding * 2;
const chartH = h - padding * 2;
ctx.strokeStyle = '#e8e4df'; ctx.lineWidth = 1;
for (let i = 0; i <= 5; i++) {
const y = padding + (chartH / 5) * i;
ctx.beginPath(); ctx.moveTo(padding, y); ctx.lineTo(w - padding, y); ctx.stroke();
}
ctx.strokeStyle = '#e85a8a'; ctx.lineWidth = 3; ctx.beginPath();
days.forEach((d, i) => {
const x = padding + (chartW / (days.length - 1)) * i;
const y = padding + chartH - (probs[i] / 100) * chartH;
if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
});
ctx.stroke();
ctx.fillStyle = '#e85a8a';
days.forEach((d, i) => {
const x = padding + (chartW / (days.length - 1)) * i;
const y = padding + chartH - (probs[i] / 100) * chartH;
ctx.beginPath(); ctx.arc(x, y, 5, 0, Math.PI * 2); ctx.fill();
});
ctx.fillStyle = '#8a8a8a'; ctx.font = '12px Segoe UI'; ctx.textAlign = 'center';
days.forEach((d, i) => {
const x = padding + (chartW / (days.length - 1)) * i;
ctx.fillText((d > 0 ? '+' : '') + d + 'd', x, h - 15);
});
}
// Init chart
renderFertilityCurve();
All calculations are performed locally. Your cycle data never leaves your browser.