{
const margin = 200;
const marginRight = margin;
const [canvasWidth, canvasHeight] = [width, 700];
const [insetWidth, insetHeight] = [canvasWidth - margin - marginRight, canvasHeight - margin * 2];
const scale = Math.min(insetWidth / (lngRange[1] - lngRange[0]),
insetHeight / (latRange[1] - latRange[0]));
const centerLng = (lngRange[0] + lngRange[1]) / 2;
const centerLat = (latRange[0] + latRange[1]) / 2;
const centerX = margin + insetWidth / 2;
const centerY = canvasHeight / 2;
const lngToX = (lng) => (lng - centerLng) * scale + centerX;
const latToY = (lat) => -(lat - centerLat) * scale + centerY;
const ctx = DOM.context2d(canvasWidth, canvasHeight);
ctx.beginPath();
latlngs.forEach((latlng, i) => {
const [x, y] = [lngToX(latlng[1] * lngFactor), latToY(latlng[0])];
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
});
ctx.stroke();
const curLat = elementInterpolated(lats, curIdx);
const curLng = elementInterpolated(lngs, curIdx);
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(lngToX(curLng), latToY(curLat), 3, 0, Math.PI * 2, true);
ctx.fill();
const ringRadius = insetHeight * 0.5
const actStartSecs = +(new Date(actData.start_date)) / 1000;
tracks.forEach(track => {
const offsetSecs = track.date.uts - actStartSecs;
const idx = indexInterpolated(secsData, offsetSecs);
const curLat = elementInterpolated(lats, idx);
const curLng = elementInterpolated(lngs, idx);
const [x, y] = [lngToX(curLng), latToY(curLat)];
const n = ringRadius / Math.hypot(x - centerX, y - centerY);
const [xN, yN] = [(x - centerX) * n + centerX, (y - centerY) * n + centerY];
ctx.strokeStyle = '#f00';
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(xN, yN);
ctx.stroke();
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2, true);
ctx.fill();
ctx.fillStyle = 'gray';
ctx.font = '12px Arial';
const msg = `${track.artist["#text"]} - ${track.name}`;
ctx.textAlign = xN < centerX ? "end" : "start";
const offset = xN < centerX ? -5 : 5;
ctx.fillText(msg, xN + offset, yN + 6);
});
return ctx.canvas;
}