Skip to content

Commit 74bd605

Browse files
authored
Merge pull request #32 from AlecM33/savant-sliders
Savant sliders
2 parents 14f4745 + c3818ee commit 74bd605

File tree

1 file changed

+75
-55
lines changed

1 file changed

+75
-55
lines changed

modules/command-util.js

+75-55
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,8 @@ module.exports = {
318318
buildSavantSection(value, metricSummaries) +
319319
'<h3>Hitting</h3>' +
320320
buildSavantSection(hitting, metricSummaries) +
321-
'<h3>Fielding</h3>' +
322-
buildSavantSection(fielding, metricSummaries) +
323-
(statcast.blocks_above_average !== null ? '<h3>Catching</h3>' + buildSavantSection(catching, metricSummaries) : '') +
321+
(fielding.find(stat => stat.value !== null) ? '<h3>Fielding</h3>' + buildSavantSection(fielding, metricSummaries) : '') +
322+
(catching.find(stat => stat.value !== null) ? '<h3>Catching</h3>' + buildSavantSection(catching, metricSummaries) : '') +
324323
'<h3>Running</h3>' +
325324
buildSavantSection(running, metricSummaries) +
326325
'</div>';
@@ -352,9 +351,9 @@ module.exports = {
352351
const html = `
353352
<div id='savant-table'>` +
354353
'<h3>Value</h3>' +
355-
buildSavantSection(value, metricSummaries) +
354+
buildSavantSection(value, metricSummaries, true) +
356355
'<h3>Pitching</h3>' +
357-
buildSavantSection(pitching, metricSummaries) +
356+
buildSavantSection(pitching, metricSummaries, true) +
358357
'</div>';
359358

360359
return (await getScreenshotOfSavantTable(html));
@@ -699,20 +698,26 @@ async function getScreenshotOfSavantTable (savantHTML) {
699698
#savant-table {
700699
background-color: #151820;
701700
color: whitesmoke;
702-
padding: 15px;
703-
font-size: 20px;
701+
font-size: 25px;
704702
font-family: 'Segoe UI', sans-serif;
705-
width: 40%;
703+
width: 65%;
704+
display: flex;
705+
padding: 17px 27.5px 17px 10px;
706+
flex-direction: column;
707+
align-items: center;
706708
}
707709
.savant-stat {
708710
display: flex;
709-
width: 100%;
711+
width: 95%;
710712
justify-content: space-between;
711713
margin: 5px 0;
712714
align-items: center;
713715
}
716+
.savant-stat-pitcher {
717+
margin: 12px 0;
718+
}
714719
h3 {
715-
font-size: 22px;
720+
font-size: 30px;
716721
font-weight: bold;
717722
width: 100%;
718723
text-align: center;
@@ -722,46 +727,48 @@ async function getScreenshotOfSavantTable (savantHTML) {
722727
margin: 10px 0;
723728
}
724729
.percentile {
725-
width: 28px;
726-
height: 28px;
730+
width: 35px;
731+
height: 35px;
727732
font-size: 0.7em;
728733
display: flex;
729734
align-items: center;
730735
justify-content: center;
731736
font-weight: bold;
732-
border-radius: 50%
737+
border-radius: 50%;
738+
position: absolute;
739+
top: 50%;
740+
left: -20px;
741+
transform: translateY(-50%);
742+
}
743+
.percentile-slider-not-qualified {
744+
background-image: repeating-linear-gradient(
745+
-45deg,
746+
transparent,
747+
transparent 3px,
748+
rgba(0, 0, 0, 0.95) 3px,
749+
rgba(0, 0, 0, 0.95) 6px
750+
);
733751
}
734752
.percentile-not-qualified {
735-
background-image: linear-gradient(
736-
-45deg,
737-
rgba(0,0,0,0.95) 10%,
738-
transparent 10%,
739-
transparent 20%,
740-
rgba(0,0,0,0.95) 20%,
741-
rgba(0,0,0,0.95) 30%,
742-
transparent 30%,
743-
transparent 40%,
744-
rgba(0,0,0,0.95) 40%,
745-
rgba(0,0,0,0.95) 50%,
746-
transparent 50%,
747-
transparent 60%,
748-
rgba(0,0,0,0.95) 60%,
749-
rgba(0,0,0,0.95) 70%,
750-
transparent 70%,
751-
transparent 80%,
752-
rgba(0,0,0,0.95) 80%,
753-
rgba(0,0,0,0.95) 90%,
754-
transparent 90%,
755-
transparent 100%
756-
);
757-
background-size: 0.42em;
753+
display: none;
758754
}
759755
.stat-values {
760756
display: flex;
761-
width: 5em;
757+
width: 8.5em;
762758
justify-content: space-between;
763759
align-items: center;
764760
}
761+
.percentile-slider {
762+
position: relative;
763+
width: 150px;
764+
height: 0.75em;
765+
background: #80808045;
766+
}
767+
.percentile-slider-portion {
768+
position: absolute;
769+
width: 100%;
770+
height: 100%;
771+
}
765772
</style>` +
766773
savantHTML
767774
);
@@ -773,27 +780,38 @@ async function getScreenshotOfSavantTable (savantHTML) {
773780
return buffer;
774781
}
775782

776-
function buildSavantSection (statCollection, metricSummaries) {
783+
function buildSavantSection (statCollection, metricSummaries, isPitcher = false) {
777784
const scale = chroma.scale(['#325aa1', '#a8c1c3', '#c91f26']);
785+
const sliderScale = chroma.scale(['#3661ad', '#b4cfd1', '#d8221f']);
786+
statCollection.forEach(stat => {
787+
if (!stat.percentile) {
788+
stat.percentile = calculateRoundedPercentileFromNormalDistribution(
789+
stat.metric,
790+
stat.value,
791+
metricSummaries[stat.metric].avg_metric,
792+
metricSummaries[stat.metric].stddev_metric,
793+
stat.shouldInvert
794+
);
795+
stat.isQualified = false;
796+
} else {
797+
stat.isQualified = true;
798+
}
799+
});
778800
return statCollection.reduce((acc, value) => acc + (value.value !== null
779801
? `
780-
<div class='savant-stat'>
781-
<div class='label'>${value.label}</div>
782-
<div class='stat-values'>
783-
<div class='value'>${value.value}</div>
784-
<div class='percentile ${value.percentile ? '' : 'percentile-not-qualified'}' style='background-color: ${value.percentile
785-
? scale(value.percentile / 100)
786-
: scale(caculateRoundedPercentileFromNormalDistribution(
787-
value.metric,
788-
value.value,
789-
metricSummaries[value.metric].avg_metric,
790-
metricSummaries[value.metric].stddev_metric,
791-
value.shouldInvert
792-
))}'>${value.percentile || ' '}
793-
</div>
802+
<div class='savant-stat${(isPitcher ? ' savant-stat-pitcher' : '')}'>
803+
<div class='label'>${value.label}</div>
804+
<div class='stat-values'>
805+
<div class='value'>${value.value}</div>
806+
<div class='percentile-slider'>
807+
<div class='percentile-slider-portion ${value.isQualified ? '' : 'percentile-slider-not-qualified'}'
808+
style='background-color: ${sliderScale(value.percentile / 100)}; width: ${(value.percentile / 100) * 150}px'></div>
809+
<div class='percentile ${value.isQualified ? '' : 'percentile-not-qualified'}'
810+
style='background-color: ${scale(value.percentile / 100)}; left: ${-17.5 + (value.percentile / 100) * 150}px '>${value.percentile || ' '}
794811
</div>
795812
</div>
796-
`
813+
</div>
814+
</div>`
797815
: ''), '');
798816
}
799817

@@ -842,7 +860,9 @@ async function getScreenshotOfLineScore (tables, inning, half, awayScore, homeSc
842860
return buffer;
843861
}
844862

845-
function caculateRoundedPercentileFromNormalDistribution (metric, value, mean, standardDeviation, shouldInvert) {
863+
function calculateRoundedPercentileFromNormalDistribution (metric, value, mean, standardDeviation, shouldInvert) {
846864
if (typeof value === 'string') { value = parseFloat(value); }
847-
return shouldInvert ? (1.00 - ztable((value - mean) / standardDeviation)) : ztable((value - mean) / standardDeviation);
865+
return Math.round(
866+
(shouldInvert ? (1.00 - ztable((value - mean) / standardDeviation)) : ztable((value - mean) / standardDeviation)) * 100
867+
);
848868
}

0 commit comments

Comments
 (0)