function renderWeightChart() {
const svg = getSVG({ width: CHART_WIDTH, height: CHART_HEIGHT });
const INNER_WIDTH = CHART_WIDTH - PADDING * 2;
const INNER_HEIGHT = CHART_HEIGHT - PADDING * 2;
const MAX_WEIGHT = MIN_WEIGHT + WEIGHT_RANGE;
const TICK_DIM = 12;
const STROKE_WIDTH_NORMAL = 0.5;
const STROKE_WIDTH_THICK = 1;
const FONT_SIZE_NORMAL = 24;
const FONT_SIZE_SMALL = 12;
const FONT_SIZE_LARGE = 36;
const MIN_WEIGHT_LB = MIN_WEIGHT * LBS_IN_KG;
const WEIGHT_RANGE_LB = WEIGHT_RANGE * LBS_IN_KG;
const WEIGHT_RANGE_BMI = WEIGHT_RANGE / (HEIGHT_M * HEIGHT_M);
const nIncrWeight = parseInt(WEIGHT_RANGE / WEIGHT_INCR);
const nDarkWeight = parseInt(1 / WEIGHT_INCR);
let weightLbSet = new Set();
let bmiSet = new Set();
range(0, nIncrWeight + 1).forEach(function(i) {
const [x1, x2] = [PADDING - TICK_DIM, PADDING + INNER_WIDTH + TICK_DIM];
const y = PADDING + (INNER_HEIGHT * i) / nIncrWeight;
const isDark = i % nDarkWeight === 0;
const strokeWidth = isDark ? STROKE_WIDTH_THICK : STROKE_WIDTH_NORMAL;
drawLine(svg, [x1, y], [x2, y], { stroke: 'black', strokeWidth });
if (isDark) {
const weight = MAX_WEIGHT - i * WEIGHT_INCR;
drawText(svg, [PADDING * 0.25, y], weight, {
textAnchor: 'start',
fill: 'black',
fontSize: FONT_SIZE_LARGE
});
const weightLbActual = weight * LBS_IN_KG;
const weightLb = parseInt(weightLbActual / 5) * 5;
if (!weightLbSet.has(weightLb)) {
const y0 =
y + (INNER_HEIGHT * (weightLbActual - weightLb)) / WEIGHT_RANGE_LB;
drawText(svg, [PADDING * 0.01, y0], weightLb, {
textAnchor: 'start',
fill: 'black',
fontSize: FONT_SIZE_SMALL
});
weightLbSet.add(weightLb);
}
const bmiActual = weight / (HEIGHT_M * HEIGHT_M);
const bmi = parseInt(bmiActual / 0.5) * 0.5;
if (!bmiSet.has(weightLb)) {
const y0 = y + (INNER_HEIGHT * (bmiActual - bmi)) / WEIGHT_RANGE_BMI;
drawText(
svg,
[INNER_WIDTH + PADDING + PADDING / 2 + TICK_DIM, y0],
d3.format('.1f')(bmi),
{
textAnchor: 'end',
fill: 'black',
fontSize: FONT_SIZE_NORMAL
}
);
weightLbSet.add(weightLb);
}
}
});
const nIncrTime = parseInt(TIME_RANGE_DAYS / TIME_INCR);
const nDarkTime = parseInt(1 / TIME_INCR);
const dateNow = new Date();
const startTimeUnixTime =
parseInt(dateNow.getTime() / (7 * 86400 * 1000)) * 7 * 86400 * 1000 +
3 * 86400 * 1000;
range(0, nIncrTime + 1).forEach(function(i) {
const [y1, y2] = [PADDING - TICK_DIM, PADDING + INNER_HEIGHT + TICK_DIM];
const x = PADDING + (INNER_WIDTH * i) / nIncrTime;
const isDark = i % nDarkTime === 0;
const strokeWidth = isDark ? STROKE_WIDTH_THICK : STROKE_WIDTH_NORMAL;
drawLine(svg, [x, y1], [x, y2], { stroke: 'black', strokeWidth });
drawText(svg, [x, PADDING * 0.75], DAY_LIST[i % 7].substring(0, 1), {
textAnchor: 'middle',
fill: 'black',
fontSize: FONT_SIZE_SMALL
});
if (isDark) {
const date = new Date(startTimeUnixTime + i * 86400 * 1000);
const dateStr = `${MONTH_LIST[date.getMonth()].substring(
0,
3
)} ${date.getDate()}`;
drawText(svg, [x, PADDING * 0.25], dateStr, {
textAnchor: 'middle',
fill: 'black',
fontSize: FONT_SIZE_NORMAL
});
}
});
drawText(
svg,
[CHART_WIDTH / 2, CHART_HEIGHT - PADDING / 2],
`${PERSON_NAME}'s Weight Chart`,
{
textAnchor: 'middle',
fill: 'black'
}
);
return svg.node();
}