Codex commited on
Commit ·
c6ca76d
1
Parent(s): 6e99a7b
Separate pitcher plot legend panel
Browse files- src/baseball-charts.js +24 -19
src/baseball-charts.js
CHANGED
|
@@ -831,21 +831,39 @@ async function createPitcherLocationPlotPng(payload = {}) {
|
|
| 831 |
|
| 832 |
const notesX = plotX + plotWidth + 28;
|
| 833 |
const notesWidth = boardX + boardWidth - notesX - 28;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 834 |
drawMiniSummary(
|
| 835 |
ctx,
|
| 836 |
notesX,
|
| 837 |
-
plotY,
|
| 838 |
notesWidth,
|
| 839 |
-
|
| 840 |
'How To Read',
|
| 841 |
'Each dot is one pitch at its plate location. Colors identify pitch types so you can see how the arsenal is spread in and around the zone.'
|
| 842 |
);
|
| 843 |
drawMiniSummary(
|
| 844 |
ctx,
|
| 845 |
notesX,
|
| 846 |
-
plotY +
|
| 847 |
notesWidth,
|
| 848 |
-
|
| 849 |
'Pitch Mix',
|
| 850 |
(payload.pitchBreakdown ?? []).length
|
| 851 |
? payload.pitchBreakdown.map((item) => `${item.pitchName}: ${item.count} pitches (${item.pct.toFixed(0)}%)`).join(' | ')
|
|
@@ -854,26 +872,13 @@ async function createPitcherLocationPlotPng(payload = {}) {
|
|
| 854 |
drawMiniSummary(
|
| 855 |
ctx,
|
| 856 |
notesX,
|
| 857 |
-
plotY +
|
| 858 |
notesWidth,
|
| 859 |
-
|
| 860 |
'Read',
|
| 861 |
payload.read ?? 'This chart shows where each pitch type actually finishes at the plate.'
|
| 862 |
);
|
| 863 |
|
| 864 |
-
let legendY = plotY + 16;
|
| 865 |
-
for (const item of (payload.pitchBreakdown ?? []).slice(0, 6)) {
|
| 866 |
-
const color = pitchColors.get(item.pitchName) ?? '#ffffff';
|
| 867 |
-
ctx.fillStyle = color;
|
| 868 |
-
ctx.beginPath();
|
| 869 |
-
ctx.arc(notesX + 18, legendY, 6, 0, Math.PI * 2);
|
| 870 |
-
ctx.fill();
|
| 871 |
-
ctx.fillStyle = TEXT.subtitle;
|
| 872 |
-
ctx.font = '14px sans-serif';
|
| 873 |
-
ctx.fillText(item.pitchName, notesX + 34, legendY + 4);
|
| 874 |
-
legendY += 24;
|
| 875 |
-
}
|
| 876 |
-
|
| 877 |
return canvas.toBuffer('png');
|
| 878 |
}
|
| 879 |
|
|
|
|
| 831 |
|
| 832 |
const notesX = plotX + plotWidth + 28;
|
| 833 |
const notesWidth = boardX + boardWidth - notesX - 28;
|
| 834 |
+
drawPanel(ctx, notesX, plotY, notesWidth, 148, 18);
|
| 835 |
+
ctx.fillStyle = TEXT.title;
|
| 836 |
+
ctx.font = 'bold 18px sans-serif';
|
| 837 |
+
ctx.fillText('Legend', notesX + 18, plotY + 30);
|
| 838 |
+
|
| 839 |
+
let legendY = plotY + 58;
|
| 840 |
+
for (const item of (payload.pitchBreakdown ?? []).slice(0, 6)) {
|
| 841 |
+
const color = pitchColors.get(item.pitchName) ?? '#ffffff';
|
| 842 |
+
ctx.fillStyle = color;
|
| 843 |
+
ctx.beginPath();
|
| 844 |
+
ctx.arc(notesX + 20, legendY, 6, 0, Math.PI * 2);
|
| 845 |
+
ctx.fill();
|
| 846 |
+
ctx.fillStyle = TEXT.subtitle;
|
| 847 |
+
ctx.font = '14px sans-serif';
|
| 848 |
+
ctx.fillText(`${item.pitchName} (${item.pct.toFixed(0)}%)`, notesX + 36, legendY + 4);
|
| 849 |
+
legendY += 22;
|
| 850 |
+
}
|
| 851 |
+
|
| 852 |
drawMiniSummary(
|
| 853 |
ctx,
|
| 854 |
notesX,
|
| 855 |
+
plotY + 170,
|
| 856 |
notesWidth,
|
| 857 |
+
110,
|
| 858 |
'How To Read',
|
| 859 |
'Each dot is one pitch at its plate location. Colors identify pitch types so you can see how the arsenal is spread in and around the zone.'
|
| 860 |
);
|
| 861 |
drawMiniSummary(
|
| 862 |
ctx,
|
| 863 |
notesX,
|
| 864 |
+
plotY + 302,
|
| 865 |
notesWidth,
|
| 866 |
+
150,
|
| 867 |
'Pitch Mix',
|
| 868 |
(payload.pitchBreakdown ?? []).length
|
| 869 |
? payload.pitchBreakdown.map((item) => `${item.pitchName}: ${item.count} pitches (${item.pct.toFixed(0)}%)`).join(' | ')
|
|
|
|
| 872 |
drawMiniSummary(
|
| 873 |
ctx,
|
| 874 |
notesX,
|
| 875 |
+
plotY + 474,
|
| 876 |
notesWidth,
|
| 877 |
+
98,
|
| 878 |
'Read',
|
| 879 |
payload.read ?? 'This chart shows where each pitch type actually finishes at the plate.'
|
| 880 |
);
|
| 881 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 882 |
return canvas.toBuffer('png');
|
| 883 |
}
|
| 884 |
|