Added a report showing the number of 2's and 12's rolled, and SA's.

master
Pacman Ghost 4 years ago
parent 11ea8b47c2
commit 8742f7fb0f
  1. 17
      vasl_templates/webapp/static/css/lfa.css
  2. BIN
      vasl_templates/webapp/static/images/sniper.png
  3. 136
      vasl_templates/webapp/static/lfa.js
  4. 4
      vasl_templates/webapp/templates/lfa.html
  5. BIN
      vasl_templates/webapp/tests/fixtures/analyze-vlog/hotness-report-1.vlog
  6. BIN
      vasl_templates/webapp/tests/fixtures/analyze-vlog/hotness-report-2.vlog
  7. 111
      vasl_templates/webapp/tests/test_lfa.py

@ -63,7 +63,22 @@
border: 1px solid #ffc030 ; border-radius: 5px ; background: #fffcfc ;
padding: 2px 5px ;
}
#lfa .hotness img.dice { position: absolute ; left: -10px ; top : -25px ; height: 50px ; }
#lfa .hotness img.dice { position: absolute ; left: -10px ; top : -25px ; height: 50px ; cursor: pointer ; }
/* hotness popup */
#lfa .hotness-popup {
position: absolute ;
border: 1px solid #888 ; border-radius: 5px ;
padding: 0.5em ;
background: #f8f8f8 ;
z-index: 100 ;
}
#lfa .hotness-popup th { padding: 0.2em 0.5em 0 0.5em ; background: #ddd ; border: 1px dotted #ccc ; font-weight: normal ; }
#lfa .hotness-popup td.player { white-space: nowrap ; }
#lfa .hotness-popup .val { border: none ; text-align: center ; color: #444 ; }
#lfa .hotness-popup td.icon { width: 50px ; }
#lfa .hotness-popup img.die { height: 1.5em ; margin: 2px 0.2em 0 0 ; }
#lfa .hotness-popup img.sniper { height: 1.75em ; margin-top: 3px ; }
/* options panel */
#lfa .options {

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -50,7 +50,7 @@ var gDistribDatasetPlayerIndex={}, gPieDatasetPlayerIndex={}, gTimePlotDatasetPl
var gDistribCharts={}, gPieCharts={}, gTimePlotChart, gHotnessChart ;
var $gDialog ;
var $gBanner, $gHotness, $gSelectFilePopup, $gOptions, $gRollTypeDropList, $gStackBarGraphsCheckBox ;
var $gBanner, $gHotness, $gHotnessPopup, $gSelectFilePopup, $gOptions, $gRollTypeDropList, $gStackBarGraphsCheckBox ;
var $gPlayerColorsButton, $gPlayerColorsPopup ;
var $gTimePlot, $gTimePlotChartWrapper ;
var $gTimePlotOptions, $gMovingAverageDropList, $gTimePlotZoomInButton, $gTimePlotZoomOutButton ;
@ -77,11 +77,14 @@ SHORTCUT_HANDLERS = {
71: function () { // "G"
$gMovingAverageDropList.selectmenu("instance").button.focus() ;
},
88: function () { //"X"
88: function () { // "X"
var $elem = $gBanner.find( ".select-file" ) ;
if ( $elem.css( "display" ) != "none" )
$gBanner.find( ".select-file" ).click() ;
},
50: function() { // "2"
$( "#lfa .hotness img.dice" ).click() ;
},
} ;
gPrevSelectMenuKeyDownHandler = $.ui.selectmenu.prototype._buttonEvents.keydown ;
@ -170,6 +173,8 @@ window.show_lfa_dialog = function( resp )
loadDialog() ;
},
close: function() {
// NOTE: We explicitly close everything so that they aren't visible next time we open.
closeAllPopupsAndDropLists() ;
// clean up handlers
gEventHandlers.cleanUp() ;
// clean up charts
@ -195,6 +200,7 @@ function loadDialog()
// initialize
$gBanner = $( "#lfa .banner" ) ;
$gHotness = $( "#lfa .hotness" ).hide() ;
$gHotnessPopup = $( "#lfa .hotness-popup" ) ;
$gSelectFilePopup = $( "#lfa .select-file-popup" ) ;
$gOptions = $( "#lfa .options" ) ;
$gRollTypeDropList = $( "#lfa select[name='roll-type']" ) ;
@ -217,6 +223,9 @@ function loadDialog()
gLogFileAnalysis = new LogFileAnalysis( gRawResponseData, -1 ) ;
var rollTypes = gLogFileAnalysis.getRollTypes() ;
// initialize the hotness popup
initHotnessPopup() ;
// initialize the player colors
var prevColorsLen = gUserSettings.lfa[ "player-colors" ].length ; // nb: this includes the "expected results" color
gLogFileAnalysis.forEachPlayer( function( playerId, playerNo ) {
@ -343,6 +352,127 @@ function loadDialog()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function initHotnessPopup()
{
function makeReport() {
// initialize
var rolls={}, snipers={} ;
gLogFileAnalysis.forEachPlayer( function( playerId, playerNo ) {
rolls[ playerId ] = {} ;
for ( var rollType in ROLL_TYPES )
rolls[ playerId ][ rollType ] = { 2: 0, 12: 0 } ;
snipers[ playerId ] = { 1: 0, 2: 0 } ;
} ) ;
// count how many 2's and 12's were rolled, and Sniper Activations
gLogFileAnalysis.extractEvents( 1, {
onRollEvent: function( evt ) {
var rollTotal = LogFileAnalysis.rollTotal( evt.rollValue ) ;
if ( evt.rollType == "SA" && ( rollTotal == 1 || rollTotal == 2 ) )
++ snipers[ evt.playerId ][ rollTotal ] ;
else if ( ! LogFileAnalysis.isSingleDie( evt.rollValue ) && ( rollTotal == 2 || rollTotal == 12 ) )
++ rolls[ evt.playerId ][ evt.rollType ][ rollTotal ] ;
}
} ) ;
// figure out which roll types had at least one 2 or 12
var rollTypesToShow = {} ;
gLogFileAnalysis.forEachPlayer( function( playerId, playerNo ) {
for ( var rollType in ROLL_TYPES ) {
if ( rolls[playerId][rollType][2] > 0 || rolls[playerId][rollType][12] > 0 )
rollTypesToShow[ rollType ] = true ;
}
} ) ;
// add the 2's and 12's to the report
var buf = [] ;
function addRollReport( tableClass, die1, die2 ) {
// add the header
buf.push( "<table class='" + tableClass + "'>" ) ;
buf.push( "<tr>", "<td class='icon'>",
"<img src='" + makeDieImageUrl( die1, "yellow" ) + "' class='die'>",
"<img src='" + makeDieImageUrl( die2, "white" ) + "' class='die'>"
) ;
for ( var rollType in ROLL_TYPES ) {
if ( rollTypesToShow[ rollType ] )
buf.push( "<th>", rollType ) ;
}
gLogFileAnalysis.forEachPlayer( function( playerId, playerNo ) {
buf.push( "<tr>", "<td class='player'>", makePlayerNameHTML(playerId) ) ;
for ( var rollType in ROLL_TYPES ) {
if ( ! rollTypesToShow[ rollType ] )
continue ;
var nRollTypes = rolls[ playerId ][ rollType ][ die1+die2 ] ;
buf.push( "<td class='val'>", nRollTypes === 0 ? "-" : nRollTypes ) ;
}
} ) ;
buf.push( "</table>" ) ;
}
addRollReport( "2s", 1, 1 ) ;
addRollReport( "12s", 6, 6 ) ;
// add a divider
buf.push(
"<div style='height:0.25em;border-bottom:1px dotted #aaa;'>&nbsp;</div>",
"<div style='height:0.75em;'>&nbsp;</div>"
) ;
// add the Sniper Activations to the report
buf.push( "<table class='snipers'>" ) ;
buf.push( "<tr>", "<td class='icon'>",
"<img src='" + gImagesBaseUrl+"/sniper.png" + "' class='sniper'>",
"<th>", "dr 1", "<th>", "dr 2"
) ;
gLogFileAnalysis.forEachPlayer( function( playerId, playerNo ) {
buf.push( "<tr>", "<td class='player'>", makePlayerNameHTML(playerId) ) ;
[ 1, 2 ].forEach( function( val ) {
var nActivations = snipers[ playerId ][ val ] ;
buf.push( "<td class='val'>", nActivations === 0 ? "-" : nActivations ) ;
} ) ;
} ) ;
buf.push( "</table>" ) ;
// generate the report
return buf.join( "" ) ;
}
function makePlayerNameHTML( playerId ) {
return escapeHTML( gLogFileAnalysis.playerName( playerId ) ) ;
}
// add a click handler for the hotness popup
var $elem = $( "#lfa .hotness img.dice" ) ;
gEventHandlers.addHandler( $elem, "click", function( evt ) {
closeAllPopupsAndDropLists() ;
// NOTE: We have to re-generate the report each time it's shown, since the user
// may have chosen a different set of log files.
$gHotnessPopup.html( makeReport() ).show() ;
var maxWidth = 0 ;
$gHotnessPopup.find( "table" ).each( function() {
maxWidth = Math.max( $(this).outerWidth() , maxWidth ) ;
} ) ;
$gHotnessPopup.css( { width: maxWidth } ) ;
$gHotnessPopup.position( {
my: "right top", at: "left-5 top+2", of: $elem, collision: "fit"
} ) ;
stopEvent( evt ) ;
} ) ;
// handle clicks outside the popup (to dismiss it)
// NOTE: We do this by adding a click handler to the main dialog window, and a click handler
// to the popup that prevents the event from bubbling up i.e. if the main dialog window receives
// a click event, it must've been outside the popup window.
gEventHandlers.addHandler( $gHotnessPopup, "click", function() {
return false ;
} ) ;
gEventHandlers.addHandler( $("#lfa"), "click", function() {
$gHotnessPopup.hide() ;
} ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function initSelectFilePopup()
{
// initialize the file selection popup
@ -1362,6 +1492,7 @@ function customTimePlotTooltip( tooltipModel )
var newLeft = position.left + window.pageXOffset + tooltipModel.caretX + marginX ;
if ( newLeft >= position.width - tooltipElem.offsetWidth - 20 )
newLeft = tooltipModel.caretX - tooltipElem.offsetWidth ;
tooltipElem.style["z-index"] = 150 ; // nb: put this on top of the hotness popup
tooltipElem.style.left = newLeft + "px" ;
tooltipElem.style.top = position.top + window.pageYOffset + tooltipModel.caretY - tooltipElem.offsetHeight - marginY + "px" ;
tooltipElem.style.background = tooltipModel.backgroundColor ;
@ -1816,6 +1947,7 @@ function closeAllPopupsAndDropLists()
$(this).spectrum( "hide") ;
} ) ;
$gSelectFilePopup.hide() ;
$gHotnessPopup.hide() ;
// close all droplists
$( "#lfa select" ).each( function() {

@ -23,7 +23,7 @@
<div class="pie d6x2"> <canvas></canvas> </div>
<div class="hotness" title="How hot were the dice...?" style="display:none;">
<img src="{{url_for('static',filename='images/lfa/hotness.png')}}" class="dice">
<img src="{{url_for('static',filename='images/lfa/hotness.png')}}" class="dice" title="2's, 12's and Snipers">
<canvas></canvas>
</div>
@ -65,6 +65,8 @@
<div class="select-file-popup" style="display:none;"> </div>
<div class="hotness-popup" style="display:none;"> </div>
<div class="timePlot-tooltip" style="border-radius:5px;z-index:99;">
<table style="font-size:100%;"> </table>
</div>

@ -232,16 +232,6 @@ def test_multiple_files( webapp, webdriver ):
assert player_names.pop() == "expected results"
assert player_names == expected
def select_file( fname ):
"""Select one of the files being analyzed."""
find_child( "#lfa .banner .select-file" ).click()
popup = wait_for_elem( 2, "#lfa .select-file-popup" )
for row in find_children( ".row", popup ):
if find_child( "label", row ).text == fname:
find_child( "input[type='radio']", row ).click()
return
assert False, "Couldn't find file: "+fname
def do_test(): #pylint: disable=missing-docstring
# NOTE: The "1a" and "1b" log files have the same players (Alice and Bob), but the "2" log file
@ -325,7 +315,7 @@ def test_multiple_files( webapp, webdriver ):
check_color_pickers( [ "Alice", "Bob", "Chuck" ] )
# select a file and check the results
select_file( "multiple-1a.vlog" )
_select_log_file( "multiple-1a.vlog" )
_select_roll_type( "" )
lfa = _get_chart_data( 1 )
assert lfa["timePlot"] == [
@ -351,7 +341,7 @@ def test_multiple_files( webapp, webdriver ):
check_color_pickers( [ "Alice", "Bob" ] )
# select another file and check the results
select_file( "multiple-2.vlog" )
_select_log_file( "multiple-2.vlog" )
_select_roll_type( "" )
lfa = _get_chart_data( 1 )
assert lfa["timePlot"] == [
@ -376,7 +366,7 @@ def test_multiple_files( webapp, webdriver ):
check_color_pickers( [ "Bob", "Chuck" ] )
# select all files and check the results
select_file( "All files" )
_select_log_file( "All files" )
_select_roll_type( "" )
check_all_files()
check_color_pickers( [ "Alice", "Bob", "Chuck" ] )
@ -389,6 +379,91 @@ def test_multiple_files( webapp, webdriver ):
# ---------------------------------------------------------------------
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
def test_hotness_report( webapp, webdriver ):
"""Test generating the hotness popup."""
# initialize
control_tests = init_webapp( webapp, webdriver, vlog_persistence=1 )
def unload_report():
"""Unload the hotness popup."""
find_child( "#lfa .hotness img.dice" ).click()
wait_for_elem( 2, "#lfa .hotness-popup" )
report = {}
for key in ( "2s", "12s", "snipers" ):
report[ key ] = unload_table(
"//div[@class='hotness-popup']//table[@class='{}']//tr".format( key )
)
return report
def do_test(): #pylint: disable=missing-docstring
# load the test log files
# vlog #1 vlog #2
# =============== ===============
# Alice SA 1 Alice TH 2
# Bob TC 2 Chuck Rally 2
# Chuck SA 2 Alice SA 2
# Bob Rally 12 Bob TH 2
# Bob SA 1 Chuck MC 12
# Chuck SA 1 Chuck CC 2
# Bob TC 12
# Chuck MC 2
# Chuck SA 1
_analyze_vlogs( [ "hotness-report-1.vlog", "hotness-report-2.vlog" ] )
# check the hotness popup
assert unload_report() == {
"2s": [
[ "MC", "Rally", "TH", "CC", "TC" ],
[ "Alice", "-", "-", "1", "-", "-" ],
[ "Bob", "-", "-", "1", "-", "1" ],
[ "Chuck", "1", "1", "-", "1", "-" ],
],
"12s": [
[ "MC", "Rally", "TH", "CC", "TC" ],
[ "Alice", "-", "-", "-", "-", "-" ],
[ "Bob", "-", "1", "-", "-", "1" ],
[ "Chuck", "1", "-", "-", "-", "-" ],
],
"snipers": [
[ "dr 1", "dr 2" ],
[ "Alice", "1", "1" ],
[ "Bob", "1", "-" ],
[ "Chuck", "2", "1" ],
],
}
# select only one of the log files and check the hotness popup
_select_log_file( "hotness-report-2.vlog" )
assert unload_report() == {
"2s": [
[ "MC", "Rally", "TH", "CC" ],
[ "Alice", "-", "-", "1", "-" ],
[ "Bob", "-", "-", "1", "-" ],
[ "Chuck", "-", "1", "-", "1" ],
],
"12s": [
[ "MC", "Rally", "TH", "CC" ],
[ "Alice", "-", "-", "-", "-" ],
[ "Bob", "-", "-", "-", "-" ],
[ "Chuck", "1", "-", "-", "-" ],
],
"snipers": [
[ "dr 1", "dr 2" ],
[ "Alice", "-", "1" ],
[ "Bob", "-", "-" ],
[ "Chuck", "-", "-" ],
],
}
# run the tests
run_vassal_tests( control_tests, do_test, False )
# ---------------------------------------------------------------------
@pytest.mark.skipif( not pytest.config.option.vasl_mods, reason="--vasl-mods not specified" ) #pylint: disable=no-member
@pytest.mark.skipif( not pytest.config.option.vassal, reason="--vassal not specified" ) #pylint: disable=no-member
def test_3d6( webapp, webdriver ):
@ -621,6 +696,16 @@ def _check_time_plot_values( expected_window_sizes, window_size, expected ):
vals = _unload_table( "time-plot" )
assert vals == expected
def _select_log_file( fname ):
"""Select one of the log files being analyzed."""
find_child( "#lfa .banner .select-file" ).click()
popup = wait_for_elem( 2, "#lfa .select-file-popup" )
for row in find_children( ".row", popup ):
if find_child( "label", row ).text == fname:
find_child( "input[type='radio']", row ).click()
return
assert False, "Couldn't find file: "+fname
def _unload_table( sel ):
"""Unload chart data from an HTML table."""
return unload_table(

Loading…
Cancel
Save