From e197341c6f2a234b6c2b266450b8564a9125fcc1 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 22 May 2018 11:50:40 +0200 Subject: Fixing vertical positioning of match boxes if there's a single match in every phase --- jfr_playoff/generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 6d107bd..22bdc82 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -137,7 +137,8 @@ class PlayoffGenerator(object): match_height = canvas_size[1] / len(phase.matches) row_no = 0 for match in phase.matches: - grid_y = int(row_no * match_height + + grid_y = self.page['margin'] / 2 if dimensions[1] == 1 else \ + int(row_no * match_height + 0.5 * (match_height - self.page['height'])) PlayoffLogger.get('generator').info( 'grid box (%d, %d) position: (%d, %d)', -- cgit v1.2.3 From e1f1f59ecbdf749a215e631438efaf7ddc20c247 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:09:50 +0200 Subject: Storing information about seeding from starting positions in match info object --- jfr_playoff/dto.py | 4 ++++ jfr_playoff/matchinfo.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/jfr_playoff/dto.py b/jfr_playoff/dto.py index a88cd2b..fa22265 100644 --- a/jfr_playoff/dto.py +++ b/jfr_playoff/dto.py @@ -10,6 +10,10 @@ def coalesce(*arg): class Team(object): name = '' score = 0.0 + place = None + + def __init__(self): + self.place = [] def __unicode__(self): return u'%s (%.1f)' % (coalesce(self.name, ''), self.score) diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index 93b997a..5a31577 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -187,6 +187,10 @@ class MatchInfo: 'fetching HTML scores for match #%d failed: %s(%s)', self.info.id, type(e).__name__, str(e)) self.info.teams = self.__get_config_teams(self.info.teams) + for team in range(0, len(self.info.teams)): + if 'place' in self.config['teams'][team]: + self.info.teams[team].place = self.config['teams'][team]['place'] + def __get_db_board_count(self): towels = self.database.fetch( -- cgit v1.2.3 From 5dc528cbd21dbc6a372dbc021e3466e802148827 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:12:50 +0200 Subject: Expanding canvas if starting positions are to be displayed --- jfr_playoff/generator.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 22bdc82..2c68d68 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -120,19 +120,24 @@ class PlayoffGenerator(object): return '' def get_match_grid(self, dimensions, grid, matches): - canvas_size = ( + canvas_size = [ dimensions[0] * ( self.page['width'] + self.page['margin'] - ) - self.page['margin'], + ), dimensions[1] * ( self.page['height'] + self.page['margin'] - ) - self.page['margin']) + ) - self.page['margin']] + if 'starting_position_indicators' not in self.page \ + or not self.page['starting_position_indicators']: + canvas_size[0] -= self.page['margin'] PlayoffLogger.get('generator').info( 'canvas size: %s', canvas_size) grid_boxes = '' col_no = 0 for phase in grid: - grid_x = col_no * (self.page['width'] + self.page['margin']) + grid_x = col_no * self.page['width'] + (col_no + 1) * self.page['margin'] \ + if self.page['starting_position_indicators'] \ + else col_no * (self.page['width'] + self.page['margin']) grid_boxes += self.get_phase_header(phase, grid_x) match_height = canvas_size[1] / len(phase.matches) row_no = 0 -- cgit v1.2.3 From 00bb8ac06a45fd0cb960a7161a1f9cb713429a02 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:14:41 +0200 Subject: Drawing starting position boxes --- jfr_playoff/generator.py | 23 +++++++++++++++++++++++ jfr_playoff/template.py | 14 ++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 2c68d68..a42130a 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -119,6 +119,22 @@ class PlayoffGenerator(object): self.get_match_table(match)) return '' + def get_starting_position_box(self, positions, dimensions): + if 'starting_position_indicators' not in self.page \ + or not self.page['starting_position_indicators']: + return '' + boxes = '' + order = 0 + for place in sorted(positions): + boxes += self.p_temp.get( + 'STARTING_POSITION_BOX', + 0, + int(float(order) / float(len(positions)) * dimensions[1]), + place, place) + order += 1 + return boxes + + def get_match_grid(self, dimensions, grid, matches): canvas_size = [ dimensions[0] * ( @@ -134,6 +150,7 @@ class PlayoffGenerator(object): 'canvas size: %s', canvas_size) grid_boxes = '' col_no = 0 + starting_positions = set() for phase in grid: grid_x = col_no * self.page['width'] + (col_no + 1) * self.page['margin'] \ if self.page['starting_position_indicators'] \ @@ -151,8 +168,13 @@ class PlayoffGenerator(object): grid_boxes += self.get_match_box( matches[match] if match is not None else None, (grid_x, grid_y)) + if match is not None: + for team in matches[match].teams: + starting_positions.update(team.place) row_no += 1 col_no += 1 + starting_positions_boxes = self.get_starting_position_box( + starting_positions, canvas_size) return self.p_temp.get( 'MATCH_GRID', canvas_size[0], canvas_size[1], @@ -160,6 +182,7 @@ class PlayoffGenerator(object): ' '.join(['data-%s="%s"' % ( setting.replace('_', '-'), str(value) ) for setting, value in self.canvas.iteritems()]), + starting_positions_boxes, grid_boxes ) diff --git a/jfr_playoff/template.py b/jfr_playoff/template.py index 70c179b..3473530 100644 --- a/jfr_playoff/template.py +++ b/jfr_playoff/template.py @@ -51,6 +51,7 @@ class PlayoffTemplateStrings(object):
%s + %s
''' @@ -77,6 +78,19 @@ class PlayoffTemplateStrings(object): ''' + STARTING_POSITION_BOX = ''' +
+ + + + + + + +
 
%d
+
+ ''' + MATCH_BOX = '''
%s -- cgit v1.2.3 From 8a29e0818606032bdecdf794e644dbb55d5f09b5 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:15:34 +0200 Subject: Generating connector info between matches and starting positions --- jfr_playoff/generator.py | 27 +++++++++++++++++++++------ jfr_playoff/template.py | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index a42130a..9b7f31e 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -106,16 +106,31 @@ class PlayoffGenerator(object): def get_match_box(self, match, position): if match is not None: + winner_link = [ + str(m) for m in match.winner_matches + ] if match.winner_matches is not None else [] + loser_link = [ + str(m) for m in match.loser_matches + ] if match.loser_matches is not None else [] + place_loser_link = [] + place_winner_link = [] + if 'starting_position_indicators' in self.page \ + and self.page['starting_position_indicators']: + for team in match.teams: + if len(team.place) > 0: + place_link = ['place-' + str(pl) for pl in team.place] + if len(team.place) > 1: + place_loser_link += place_link + else: + place_winner_link += place_link return self.p_temp.get( 'MATCH_BOX', position[0], position[1], match.id, - ' '.join([ - str(m) for m in match.winner_matches - ]) if match.winner_matches is not None else '', - ' '.join([ - str(m) for m in match.loser_matches - ]) if match.loser_matches is not None else '', + ' '.join(winner_link), + ' '.join(loser_link), + ' '.join(place_winner_link), + ' '.join(place_loser_link), self.get_match_table(match)) return '' diff --git a/jfr_playoff/template.py b/jfr_playoff/template.py index 3473530..7b91b3b 100644 --- a/jfr_playoff/template.py +++ b/jfr_playoff/template.py @@ -92,7 +92,7 @@ class PlayoffTemplateStrings(object): ''' MATCH_BOX = ''' -
+
%s
''' -- cgit v1.2.3 From 48fac33c987be28c72e49509575e1622bfd96fc2 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:20:35 +0200 Subject: Tweaking connector offsets on canvas --- playoff.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/playoff.js b/playoff.js index a2cfa6a..890a2b6 100644 --- a/playoff.js +++ b/playoff.js @@ -1,10 +1,10 @@ var playoff = { settings: { - 'winner_h_offset': 8, - 'loser_h_offset': 14, - 'winner_v_offset': -6, - 'loser_v_offset': 6, + 'winner_h_offset': 5, + 'loser_h_offset': 20, + 'winner_v_offset': -10, + 'loser_v_offset': 10, 'loser_colour': '#ff0000', 'winner_colour': '#00ff00' }, -- cgit v1.2.3 From cf548484722bc83c18a9d771e45874cf59bc68f0 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:21:01 +0200 Subject: Refactoring of connector line drawing --- playoff.js | 139 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 70 insertions(+), 69 deletions(-) diff --git a/playoff.js b/playoff.js index 890a2b6..613bf66 100644 --- a/playoff.js +++ b/playoff.js @@ -49,99 +49,100 @@ var playoff = { } var canvas = document.getElementById('playoff_canvas'); this.settings = this.loadSettings(canvas, this.settings); - var ctx = canvas.getContext('2d'); - for (var type in lines) { - ctx.strokeStyle = this.settings[type + '_colour']; - for (var from in lines[type]) { - var to = lines[type][from]; - from = from.split(' '); - var horizontal_from = []; - var vertical_from = [0, canvas.height, 0, 0]; + var lineMethods = { + 'winner': 'midpoint', + 'loser': 'midpoint' + }; + var lineCalculator = { + correctLines: function(hLines, vLine, comparator) { + for (var l1 in hLines) { + for (var l2 in hLines) { + hLines[l1][2] = comparator(hLines[l1][2], hLines[l2][2]); + hLines[l2][2] = hLines[l1][2]; + } + } + for (var l1 in hLines) { + vLine[0] = vLine[2] = comparator(hLines[l1][2], vLine[2]); + vLine[1] = Math.min(vLine[1], hLines[l1][3]); + vLine[3] = Math.max(vLine[3], hLines[l1][3]); + } + }, + template: function() { + return { + hFrom: [], + vFrom: [0, canvas.height, 0, 0], + hTo: [], + vTo: [canvas.width, canvas.height, canvas.width, 0], + midpoints: [] + } + }, + midpoint: function(from, to, hOffset, vOffset) { + var lines = this.template(); for (var f = 0; f < from.length; f++) { var box = boxes_idx[from[f]]; var line = [ Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth)), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + parseFloat(this.settings[type + '_v_offset'])), - Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth) + parseFloat(this.settings[type + '_h_offset'])), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + parseFloat(this.settings[type + '_v_offset'])) + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth) + hOffset), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; - horizontal_from.push(line); - for (var l in horizontal_from) { - if (horizontal_from[l][2] < line[2]) { - horizontal_from[l][2] = line[2]; - } else { - line[2] = horizontal_from[l][2]; - } - if (vertical_from[0] < horizontal_from[l][2]) { - vertical_from[0] = horizontal_from[l][2]; - vertical_from[2] = horizontal_from[l][2]; - } - if (vertical_from[1] > horizontal_from[l][3]) { - vertical_from[1] = horizontal_from[l][3]; - } - if (vertical_from[3] < horizontal_from[l][3]) { - vertical_from[3] = horizontal_from[l][3]; - } - } + lines.hFrom.push(line); } - var horizontal_to = []; - var vertical_to = [canvas.width, canvas.height, canvas.width, 0]; + this.correctLines(lines.hFrom, lines.vFrom, Math.max); for (var t = 0; t < to.length; t++) { var box = boxes_idx[to[t]]; var line = [ parseInt(box.style.left), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + parseFloat(this.settings[type + '_v_offset'])), - Math.floor(parseInt(box.style.left) - parseFloat(this.settings[type + '_h_offset'])), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + parseFloat(this.settings[type + '_v_offset'])) + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.style.left) - hOffset), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; - horizontal_to.push(line); - for (var l in horizontal_to) { - if (horizontal_to[l][2] > line[2]) { - horizontal_to[l][2] = line[2]; - } else { - line[2] = horizontal_to[l][2]; - } - if (vertical_to[0] > horizontal_to[l][2]) { - vertical_to[0] = horizontal_to[l][2]; - vertical_to[2] = horizontal_to[l][2]; - } - if (vertical_to[1] > horizontal_to[l][3]) { - vertical_to[1] = horizontal_to[l][3]; - } - if (vertical_to[3] < horizontal_to[l][3]) { - vertical_to[3] = horizontal_to[l][3]; - } - } + lines.hTo.push(line); } - var midpoints = [ + this.correctLines(lines.hTo, lines.vTo, Math.min); + lines.midpoints = [ [ - (vertical_from[0] + vertical_from[2]) / 2, - (vertical_from[1] + vertical_from[3]) / 2 + (lines.vFrom[0] + lines.vFrom[2]) / 2, + (lines.vFrom[1] + lines.vFrom[3]) / 2 ], [ - parseFloat(this.settings[type + '_h_offset']) / 2 + (vertical_from[0] + vertical_from[2] + vertical_to[0] + vertical_to[2]) / 4, - (vertical_from[1] + vertical_from[3]) / 2 + hOffset / 2 + (lines.vFrom[0] + lines.vFrom[2] + lines.vTo[0] + lines.vTo[2]) / 4, + (lines.vFrom[1] + lines.vFrom[3]) / 2 ], [ - parseFloat(this.settings[type + '_h_offset']) / 2 + (vertical_from[0] + vertical_from[2] + vertical_to[0] + vertical_to[2]) / 4, - (vertical_to[1] + vertical_to[3]) / 2 + hOffset / 2 + (lines.vFrom[0] + lines.vFrom[2] + lines.vTo[0] + lines.vTo[2]) / 4, + (lines.vTo[1] + lines.vTo[3]) / 2 ], [ - (vertical_to[0] + vertical_to[2]) / 2, - (vertical_to[1] + vertical_to[3]) / 2 + (lines.vTo[0] + lines.vTo[2]) / 2, + (lines.vTo[1] + lines.vTo[3]) / 2 ] ] - for (var l in horizontal_from) { - this.drawLine(ctx, horizontal_from[l]); + return lines; + } + }; + var ctx = canvas.getContext('2d'); + for (var type in lines) { + styleType = type.replace('-', '_'); + ctx.strokeStyle = this.settings[styleType + '_colour']; + for (var from in lines[type]) { + var to = lines[type][from]; + from = from.split(' '); + var linesToDraw = lineCalculator[lineMethods[type]]( + from, to, + this.settings[styleType + '_h_offset'], this.settings[styleType + '_v_offset']); + for (var l in linesToDraw.hFrom) { + this.drawLine(ctx, linesToDraw.hFrom[l]); } - this.drawLine(ctx, vertical_from); - for (var l in horizontal_to) { - this.drawLine(ctx, horizontal_to[l]); + this.drawLine(ctx, linesToDraw.vFrom); + for (var l in linesToDraw.hTo) { + this.drawLine(ctx, linesToDraw.hTo[l]); } - this.drawLine(ctx, vertical_to); - for (var m = 0; m < midpoints.length-1; m++) { + this.drawLine(ctx, linesToDraw.vTo); + for (var m = 0; m < linesToDraw.midpoints.length-1; m++) { this.drawLine(ctx, [ - midpoints[m][0], midpoints[m][1], midpoints[m+1][0], midpoints[m+1][1] + linesToDraw.midpoints[m][0], linesToDraw.midpoints[m][1], + linesToDraw.midpoints[m+1][0], linesToDraw.midpoints[m+1][1] ]); } } -- cgit v1.2.3 From a68f22c766792e98371693a856a26bc6f67c59ce Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 01:21:43 +0200 Subject: Adding drawing methods for starting position connectors --- playoff.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/playoff.js b/playoff.js index 613bf66..c118f58 100644 --- a/playoff.js +++ b/playoff.js @@ -6,7 +6,13 @@ var playoff = { 'winner_v_offset': -10, 'loser_v_offset': 10, 'loser_colour': '#ff0000', - 'winner_colour': '#00ff00' + 'winner_colour': '#00ff00', + 'place_winner_h_offset': 10, + 'place_loser_h_offset': 15, + 'place_winner_v_offset': 8, + 'place_loser_v_offset': 14, + 'place_loser_colour': '#dddd00', + 'place_winner_colour': '#00dddd' }, drawLine: function(ctx, line) { @@ -31,7 +37,9 @@ var playoff = { var boxes = document.getElementsByClassName('playoff_matchbox'); var lines = { 'winner': {}, - 'loser': {} + 'loser': {}, + 'place-winner': {}, + 'place-loser': {} }; var boxes_idx = {}; for (var b = 0; b < boxes.length; b++) { @@ -50,6 +58,8 @@ var playoff = { var canvas = document.getElementById('playoff_canvas'); this.settings = this.loadSettings(canvas, this.settings); var lineMethods = { + 'place-winner': 'to', + 'place-loser': 'to', 'winner': 'midpoint', 'loser': 'midpoint' }; @@ -76,6 +86,66 @@ var playoff = { midpoints: [] } }, + from: function(from, to, hOffset, vOffset) { + var lines = this.template(); + for (var f = 0; f < from.length; f++) { + var box = boxes_idx[from[f]]; + var line = [ + Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth)), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth) + hOffset), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + ]; + lines.hFrom.push(line); + } + this.correctLines(lines.hFrom, lines.vFrom, Math.max); + for (var t = 0; t < to.length; t++) { + var box = boxes_idx[to[t]]; + var line = [ + lines.vFrom[0], + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.style.left) - hOffset), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + ]; + lines.hTo.push(line); + } + this.correctLines(lines.hTo, lines.vTo, Math.min); + lines.midpoints = [ + [lines.vFrom[0], lines.vFrom[1]], + [lines.vTo[0], lines.vTo[1]] + ]; + return lines; + }, + to: function(from, to, hOffset, vOffset) { + var lines = this.template(); + for (var t = 0; t < to.length; t++) { + var box = boxes_idx[to[t]]; + var line = [ + parseInt(box.style.left), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.style.left) - hOffset), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + ]; + lines.hTo.push(line); + } + this.correctLines(lines.hTo, lines.vTo, Math.min); + for (var f = 0; f < from.length; f++) { + var box = boxes_idx[from[f]]; + var line = [ + Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth)), + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + lines.vTo[0], + Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + ]; + lines.hFrom.push(line); + } + this.correctLines(lines.hFrom, lines.vFrom, Math.max); + lines.midpoints = [ + [lines.vFrom[0], lines.vFrom[1]], + [lines.vTo[0], lines.vTo[1]] + ]; + return lines; + }, midpoint: function(from, to, hOffset, vOffset) { var lines = this.template(); for (var f = 0; f < from.length; f++) { -- cgit v1.2.3 From 1e3d4e3233a9d01a81525255ed0f1479a96c1e5d Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:15:15 +0200 Subject: Fixing box offsets for line drawing --- playoff.js | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/playoff.js b/playoff.js index c118f58..301f86c 100644 --- a/playoff.js +++ b/playoff.js @@ -91,10 +91,10 @@ var playoff = { for (var f = 0; f < from.length; f++) { var box = boxes_idx[from[f]]; var line = [ - Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth)), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), - Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth) + hOffset), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + Math.floor(parseInt(box.offsetLeft) + parseInt(box.clientWidth)), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.offsetLeft) + parseInt(box.clientWidth) + hOffset), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; lines.hFrom.push(line); } @@ -102,10 +102,10 @@ var playoff = { for (var t = 0; t < to.length; t++) { var box = boxes_idx[to[t]]; var line = [ + Math.floor(parseInt(box.offsetLeft)), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset), lines.vFrom[0], - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), - Math.floor(parseInt(box.style.left) - hOffset), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; lines.hTo.push(line); } @@ -121,10 +121,10 @@ var playoff = { for (var t = 0; t < to.length; t++) { var box = boxes_idx[to[t]]; var line = [ - parseInt(box.style.left), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), - Math.floor(parseInt(box.style.left) - hOffset), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + parseInt(box.offsetLeft), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.offsetLeft) - hOffset), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; lines.hTo.push(line); } @@ -132,10 +132,10 @@ var playoff = { for (var f = 0; f < from.length; f++) { var box = boxes_idx[from[f]]; var line = [ - Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth)), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.offsetLeft) + parseInt(box.clientWidth)), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset), lines.vTo[0], - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; lines.hFrom.push(line); } @@ -151,10 +151,10 @@ var playoff = { for (var f = 0; f < from.length; f++) { var box = boxes_idx[from[f]]; var line = [ - Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth)), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), - Math.floor(parseInt(box.style.left) + parseInt(box.clientWidth) + hOffset), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + Math.floor(parseInt(box.offsetLeft) + parseInt(box.clientWidth)), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.offsetLeft) + parseInt(box.clientWidth) + hOffset), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; lines.hFrom.push(line); } @@ -162,10 +162,10 @@ var playoff = { for (var t = 0; t < to.length; t++) { var box = boxes_idx[to[t]]; var line = [ - parseInt(box.style.left), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset), - Math.floor(parseInt(box.style.left) - hOffset), - Math.floor(parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + vOffset) + parseInt(box.offsetLeft), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset), + Math.floor(parseInt(box.offsetLeft) - hOffset), + Math.floor(parseInt(box.offsetTop) + 0.5 * parseInt(box.clientHeight) + vOffset) ]; lines.hTo.push(line); } -- cgit v1.2.3 From ac0733c36b6200aecb2c738a549d00d7c2e6be98 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:20:13 +0200 Subject: Storing finishing positions in DTO --- jfr_playoff/dto.py | 2 ++ jfr_playoff/matchinfo.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/jfr_playoff/dto.py b/jfr_playoff/dto.py index fa22265..1bc153c 100644 --- a/jfr_playoff/dto.py +++ b/jfr_playoff/dto.py @@ -31,6 +31,8 @@ class Match(object): loser = None winner_matches = None loser_matches = None + winner_place = None + loser_place = None def __repr__(self): return (u'#%d (%s) %s [%s]' % ( diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index 5a31577..a7c4064 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -32,6 +32,8 @@ class MatchInfo: self.info.loser_matches += self.config['teams'][i]['loser'] self.info.winner_matches = list(set(self.info.winner_matches)) self.info.loser_matches = list(set(self.info.loser_matches)) + self.info.winner_place = self.config['winner'] if 'winner' in self.config else [] + self.info.loser_place = self.config['loser'] if 'loser' in self.config else [] self.info.teams = [] def __fetch_match_link(self): -- cgit v1.2.3 From f883784164de0a72ce61e8b225435de337ead2ed Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:22:38 +0200 Subject: Rendering position box independent from starting/finishing role --- jfr_playoff/generator.py | 3 ++- jfr_playoff/template.py | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 6a184fb..b72c34d 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -145,7 +145,8 @@ class PlayoffGenerator(object): 'STARTING_POSITION_BOX', 0, int(float(order) / float(len(positions)) * dimensions[1]), - place, place) + place, + self.p_temp.get('POSITION_BOX', place)) order += 1 return boxes diff --git a/jfr_playoff/template.py b/jfr_playoff/template.py index 7b91b3b..881e1b5 100644 --- a/jfr_playoff/template.py +++ b/jfr_playoff/template.py @@ -80,15 +80,16 @@ class PlayoffTemplateStrings(object): STARTING_POSITION_BOX = '''
+ %s +
+ ''' + + POSITION_BOX = ''' - - -
 
%d
-
''' MATCH_BOX = ''' -- cgit v1.2.3 From 7ed51a63ac7aea8da6de888b04164b945ef745b5 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:23:47 +0200 Subject: Adding vertical margin to starting position boxes --- jfr_playoff/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index b72c34d..0680aba 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -144,7 +144,7 @@ class PlayoffGenerator(object): boxes += self.p_temp.get( 'STARTING_POSITION_BOX', 0, - int(float(order) / float(len(positions)) * dimensions[1]), + self.page['margin'] / 2 + int(float(order) / float(len(positions)) * dimensions[1]), place, self.p_temp.get('POSITION_BOX', place)) order += 1 -- cgit v1.2.3 From 780c61d23789d80351476977f25699b2b5ec4c5d Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:24:41 +0200 Subject: Expanding canvas if finishing positions are rendered --- jfr_playoff/generator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 0680aba..b5c5e83 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -155,13 +155,16 @@ class PlayoffGenerator(object): canvas_size = [ dimensions[0] * ( self.page['width'] + self.page['margin'] - ), + ) + self.page['margin'], dimensions[1] * ( self.page['height'] + self.page['margin'] ) - self.page['margin']] if 'starting_position_indicators' not in self.page \ or not self.page['starting_position_indicators']: canvas_size[0] -= self.page['margin'] + if 'finishing_position_indicators' not in self.page \ + or not self.page['finishing_position_indicators']: + canvas_size[0] -= self.page['margin'] PlayoffLogger.get('generator').info( 'canvas size: %s', canvas_size) grid_boxes = '' -- cgit v1.2.3 From 31fb6dfb977fca26cf4eeb539b9f4d83f42b6a40 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:26:26 +0200 Subject: Rendering finishing boxes with connector data --- jfr_playoff/generator.py | 38 ++++++++++++++++++++++++++++++++++---- jfr_playoff/template.py | 7 +++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index b5c5e83..ef83a73 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -150,6 +150,22 @@ class PlayoffGenerator(object): order += 1 return boxes + def get_finishing_position_box(self, positions, position_info, dimensions, margin): + if 'finishing_position_indicators' not in self.page \ + or not self.page['finishing_position_indicators']: + return '' + boxes = '' + order = 0 + for place in sorted(positions): + boxes += self.p_temp.get( + 'FINISHING_POSITION_BOX', + self.page['margin'] / 2 + int(float(order) / float(len(positions)) * dimensions[1]), + place, + ' '.join([str(p) for p in position_info[place]['winner']]), + ' '.join([str(p) for p in position_info[place]['loser']]), + self.p_temp.get('POSITION_BOX', place)) + order += 1 + return boxes def get_match_grid(self, dimensions, grid, matches): canvas_size = [ @@ -170,6 +186,8 @@ class PlayoffGenerator(object): grid_boxes = '' col_no = 0 starting_positions = set() + finishing_positions = {} + finishing_places = set() for phase in grid: grid_x = col_no * self.page['width'] + (col_no + 1) * self.page['margin'] \ if self.page['starting_position_indicators'] \ @@ -190,10 +208,19 @@ class PlayoffGenerator(object): if match is not None: for team in matches[match].teams: starting_positions.update(team.place) + for place in matches[match].loser_place + matches[match].winner_place: + if place not in finishing_positions: + finishing_positions[place] = { + 'winner': [], + 'loser': [] + } + finishing_places.add(place) + for place in matches[match].winner_place: + finishing_positions[place]['winner'].append(match) + for place in matches[match].loser_place: + finishing_positions[place]['loser'].append(match) row_no += 1 col_no += 1 - starting_positions_boxes = self.get_starting_position_box( - starting_positions, canvas_size) return self.p_temp.get( 'MATCH_GRID', canvas_size[0], canvas_size[1], @@ -201,8 +228,11 @@ class PlayoffGenerator(object): ' '.join(['data-%s="%s"' % ( setting.replace('_', '-'), str(value) ) for setting, value in self.canvas.iteritems()]), - starting_positions_boxes, - grid_boxes + self.get_starting_position_box(starting_positions, canvas_size), + grid_boxes, + self.get_finishing_position_box( + finishing_places, finishing_positions, canvas_size, self.page['margin'] + ) ) def get_leaderboard_row_class(self, position): diff --git a/jfr_playoff/template.py b/jfr_playoff/template.py index 881e1b5..267c5f7 100644 --- a/jfr_playoff/template.py +++ b/jfr_playoff/template.py @@ -52,6 +52,7 @@ class PlayoffTemplateStrings(object): %s %s + %s
''' @@ -84,6 +85,12 @@ class PlayoffTemplateStrings(object): ''' + FINISHING_POSITION_BOX = ''' +
+ %s +
+ ''' + POSITION_BOX = ''' -- cgit v1.2.3 From acfc6044e25c7ff7d56a62dc1f62c21a7546f560 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:28:29 +0200 Subject: Rendering connectors for finishing positions --- playoff.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/playoff.js b/playoff.js index 301f86c..a648b4b 100644 --- a/playoff.js +++ b/playoff.js @@ -3,8 +3,12 @@ var playoff = { settings: { 'winner_h_offset': 5, 'loser_h_offset': 20, + 'finish_winner_h_offset': 5, + 'finish_loser_h_offset': 20, 'winner_v_offset': -10, 'loser_v_offset': 10, + 'finish_winner_v_offset': -4, + 'finish_loser_v_offset': 4, 'loser_colour': '#ff0000', 'winner_colour': '#00ff00', 'place_winner_h_offset': 10, @@ -12,7 +16,9 @@ var playoff = { 'place_winner_v_offset': 8, 'place_loser_v_offset': 14, 'place_loser_colour': '#dddd00', - 'place_winner_colour': '#00dddd' + 'place_winner_colour': '#00dddd', + 'finish_loser_colour': '#ff0000', + 'finish_winner_colour': '#00ff00' }, drawLine: function(ctx, line) { @@ -39,7 +45,9 @@ var playoff = { 'winner': {}, 'loser': {}, 'place-winner': {}, - 'place-loser': {} + 'place-loser': {}, + 'finish-winner': {}, + 'finish-loser': {} }; var boxes_idx = {}; for (var b = 0; b < boxes.length; b++) { @@ -60,6 +68,8 @@ var playoff = { var lineMethods = { 'place-winner': 'to', 'place-loser': 'to', + 'finish-winner': 'midpoint', + 'finish-loser': 'midpoint', 'winner': 'midpoint', 'loser': 'midpoint' }; -- cgit v1.2.3 From 3b49b542ca32d602722a3f4ba5c185242d7e5dc1 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 03:28:53 +0200 Subject: Adjusting connector parameters --- playoff.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/playoff.js b/playoff.js index a648b4b..3b57cdf 100644 --- a/playoff.js +++ b/playoff.js @@ -3,18 +3,18 @@ var playoff = { settings: { 'winner_h_offset': 5, 'loser_h_offset': 20, + 'place_winner_h_offset': 10, + 'place_loser_h_offset': 15, 'finish_winner_h_offset': 5, 'finish_loser_h_offset': 20, 'winner_v_offset': -10, 'loser_v_offset': 10, + 'place_winner_v_offset': 2, + 'place_loser_v_offset': 9, 'finish_winner_v_offset': -4, 'finish_loser_v_offset': 4, 'loser_colour': '#ff0000', 'winner_colour': '#00ff00', - 'place_winner_h_offset': 10, - 'place_loser_h_offset': 15, - 'place_winner_v_offset': 8, - 'place_loser_v_offset': 14, 'place_loser_colour': '#dddd00', 'place_winner_colour': '#00dddd', 'finish_loser_colour': '#ff0000', -- cgit v1.2.3 From 216d9673887196a0b8c2475081b115944bbff233 Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 13:58:02 +0200 Subject: Position boxes documentation --- CONFIG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CONFIG.md b/CONFIG.md index 906081f..391e2b2 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -25,10 +25,14 @@ Konfiguracja składa się, po kolei, z: + `"refresh"` - parametr odświeżania strony drabinki: `0` = wyłączone, liczba naturalna = interwał odświeżania, w sekundach + `"width"` i `"height"` - wymiary (w pikselach) miejsca rezerwowanego dla każdego meczu w widoku drabinki (`"width"` bezpośrednio wpływa na rozmieszczanie kolumn, wewnątrz każdej z kolumn mecze rozmieszczane są równomiernie, w zależnie od ich liczby) + `"margin"` - odstęp między w/w miejscem (minimalny - jak widać, w przypadku mniejszej liczby meczów w fazie, odstępy się dopasują) + + `"starting_position_indicators"`, `"finishing_position_indicators"` - włączają znaczniki miejsc początkowych/końcowych, wynikających ze zdefiniowanego schematu - sekcji `"canvas"`: ustawień rysowania linii + + `"winner_colour"`, `"loser_colour"` - kolory linii zwycięzców i przegranych + + `"place_winner_colour"`, `"place_loser_colour"` - kolory linii łączących początkowe miejsca drużyn z pierwszymi meczami (`loser` - drużyny mogące zagrać w więcej niż jednym meczu, czyli wybierane) + + `"finish_winner_colour"`, `"finish_loser_colour"` - kolory linii łączących końcowe miejsca drużyn z ich ostatnimi meczami + `"winner_h_offset"`, `"winner_v_offset"` - marginesy (poziomy i pionowy) rysowania linii zwycięzców (odpowiednio: pionowych i poziomych, względem środka obszaru) + `"loser_h_offset"`, `"loser_v_offset"` - analogiczne marginesy rysowania linii przegranych - + `"winner_colour"`, `"loser_colour"` - kolory linii zwycięzców i przegranych + + `"place_winner_h_offset"`, `"place_winner_v_offset"`, `"place_loser_h_offset"`, `"place_loser_v_offset"`, `"finish_winner_h_offset"`, `"finish_winner_v_offset"`, `"finish_loser_h_offset"`, `"finish_loser_v_offset"` - marginesy rysowania linii łączących mecze z miejscami początkowymi/końcowymi - sekcji `"database"`, zawierającej ustawienia połączenia bazy danych - sekcji `"goniec"`, zawierającej ustawienia Gońca (`"enabled"` przyjmuje wartości `0`/`1`) -- cgit v1.2.3 From 6bc2303307a24ac1ad53eedde461dedb25ec157c Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 14:20:49 +0200 Subject: Allowing for custom positioning of match boxes --- jfr_playoff/generator.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index ef83a73..12a4365 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -200,8 +200,17 @@ class PlayoffGenerator(object): int(row_no * match_height + 0.5 * (match_height - self.page['height'])) PlayoffLogger.get('generator').info( - 'grid box (%d, %d) position: (%d, %d)', + 'calculated grid box (%d, %d) position: (%d, %d)', col_no, row_no, grid_x, grid_y) + if 'box_positioning' in self.canvas \ + and str(match) in self.canvas['box_positioning']: + if isinstance(self.canvas['box_positioning'][str(match)], list): + grid_x, grid_y = self.canvas['box_positioning'][str(match)][0:2] + else: + grid_y = float(self.canvas['box_positioning'][str(match)]) + PlayoffLogger.get('generator').info( + 'overridden box #%d position: (%d, %d)', + match, grid_x, grid_y) grid_boxes += self.get_match_box( matches[match] if match is not None else None, (grid_x, grid_y)) @@ -227,7 +236,7 @@ class PlayoffGenerator(object): canvas_size[0], canvas_size[1], ' '.join(['data-%s="%s"' % ( setting.replace('_', '-'), str(value) - ) for setting, value in self.canvas.iteritems()]), + ) for setting, value in self.canvas.iteritems() if not isinstance(value, dict)]), self.get_starting_position_box(starting_positions, canvas_size), grid_boxes, self.get_finishing_position_box( -- cgit v1.2.3 From 34ca26ef666e69d2a5123d4ca37dde7845305a9e Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 6 Jul 2018 14:23:10 +0200 Subject: Docuemntation for custom box positioning --- CONFIG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONFIG.md b/CONFIG.md index 391e2b2..eac0d71 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -33,6 +33,7 @@ Konfiguracja składa się, po kolei, z: + `"winner_h_offset"`, `"winner_v_offset"` - marginesy (poziomy i pionowy) rysowania linii zwycięzców (odpowiednio: pionowych i poziomych, względem środka obszaru) + `"loser_h_offset"`, `"loser_v_offset"` - analogiczne marginesy rysowania linii przegranych + `"place_winner_h_offset"`, `"place_winner_v_offset"`, `"place_loser_h_offset"`, `"place_loser_v_offset"`, `"finish_winner_h_offset"`, `"finish_winner_v_offset"`, `"finish_loser_h_offset"`, `"finish_loser_v_offset"` - marginesy rysowania linii łączących mecze z miejscami początkowymi/końcowymi + + `"box_positioning"`: możliwość ręcznego ustawienia pozycji każdego meczu - słownik indeksowany tekstowymi identyfikatorami meczów, z wartościami liczbowymi: pojedyncza wartość = pozycja w pionie w pikselach, w ramach fazy meczu, tablica dwóch wartości: dowolna pozycja w pikselach - sekcji `"database"`, zawierającej ustawienia połączenia bazy danych - sekcji `"goniec"`, zawierającej ustawienia Gońca (`"enabled"` przyjmuje wartości `0`/`1`) -- cgit v1.2.3 From 5cf43985f96daa156d1b201ce4f5b8e925c7c711 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 10 Jul 2018 16:34:14 +0200 Subject: Sanitizing config options --- jfr_playoff/generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index ef83a73..a90cf77 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -190,7 +190,8 @@ class PlayoffGenerator(object): finishing_places = set() for phase in grid: grid_x = col_no * self.page['width'] + (col_no + 1) * self.page['margin'] \ - if self.page['starting_position_indicators'] \ + if 'starting_position_indicators' in self.page \ + and self.page['starting_position_indicators'] \ else col_no * (self.page['width'] + self.page['margin']) grid_boxes += self.get_phase_header(phase, grid_x) match_height = canvas_size[1] / len(phase.matches) -- cgit v1.2.3 From 17b67eec50d428383406d4309bc7506fd22015db Mon Sep 17 00:00:00 2001 From: emkael Date: Fri, 28 Sep 2018 17:45:52 +0200 Subject: Refactoring fetching default values for config dictionaries --- jfr_playoff/generator.py | 9 +++------ jfr_playoff/matchinfo.py | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 19b8c1d..c2fba28 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -117,8 +117,7 @@ class PlayoffGenerator(object): ] if match.loser_matches is not None else [] place_loser_link = [] place_winner_link = [] - if 'starting_position_indicators' in self.page \ - and self.page['starting_position_indicators']: + if self.page.get('starting_position_indicators', None): for team in match.teams: if len(team.place) > 0: place_link = ['place-' + str(pl) for pl in team.place] @@ -193,8 +192,7 @@ class PlayoffGenerator(object): finishing_places = set() for phase in grid: grid_x = col_no * self.page['width'] + (col_no + 1) * self.page['margin'] \ - if 'starting_position_indicators' in self.page \ - and self.page['starting_position_indicators'] \ + if self.page.get('starting_position_indicators', None) \ else col_no * (self.page['width'] + self.page['margin']) grid_boxes += self.get_phase_header(phase, grid_x) match_height = canvas_size[1] / len(phase.matches) @@ -206,8 +204,7 @@ class PlayoffGenerator(object): PlayoffLogger.get('generator').info( 'calculated grid box (%d, %d) position: (%d, %d)', col_no, row_no, grid_x, grid_y) - if 'box_positioning' in self.canvas \ - and str(match) in self.canvas['box_positioning']: + if str(match) in self.canvas.get('box_positioning', {}): if isinstance(self.canvas['box_positioning'][str(match)], list): grid_x, grid_y = self.canvas['box_positioning'][str(match)][0:2] else: diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index 4089a76..3e4d913 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -32,8 +32,8 @@ class MatchInfo: self.info.loser_matches += self.config['teams'][i]['loser'] self.info.winner_matches = list(set(self.info.winner_matches)) self.info.loser_matches = list(set(self.info.loser_matches)) - self.info.winner_place = self.config['winner'] if 'winner' in self.config else [] - self.info.loser_place = self.config['loser'] if 'loser' in self.config else [] + self.info.winner_place = self.config.get('winner', []) + self.info.loser_place = self.config.get('loser', []) self.info.teams = [] def __fetch_match_link(self): @@ -215,8 +215,8 @@ class MatchInfo: self.info.id, type(e).__name__, str(e)) self.info.teams = self.__get_config_teams(self.info.teams) for team in range(0, len(self.info.teams)): - if 'place' in self.config['teams'][team]: - self.info.teams[team].place = self.config['teams'][team]['place'] + self.info.teams[team].place = self.config['teams'][team].get( + 'place', self.info.teams[team].place) def __get_db_board_count(self): -- cgit v1.2.3 From 6f147d1b37de5c12b77c51ca2f80031cbec6ae20 Mon Sep 17 00:00:00 2001 From: emkael Date: Mon, 1 Oct 2018 14:54:58 +0200 Subject: Refactoring team name list in matches as actual list --- jfr_playoff/dto.py | 5 ++++- jfr_playoff/generator.py | 12 ++++++------ jfr_playoff/matchinfo.py | 37 +++++++++++++++++++------------------ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/jfr_playoff/dto.py b/jfr_playoff/dto.py index a88cd2b..ad70735 100644 --- a/jfr_playoff/dto.py +++ b/jfr_playoff/dto.py @@ -8,9 +8,12 @@ def coalesce(*arg): class Team(object): - name = '' + name = None score = 0.0 + def __init__(self): + self.name = [] + def __unicode__(self): return u'%s (%.1f)' % (coalesce(self.name, ''), self.score) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index d358d86..a1b519e 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -55,23 +55,23 @@ class PlayoffGenerator(object): for team in match.teams: score_html = self.p_temp.get('MATCH_SCORE', team.score) team_label = ' / '.join([ - self.data.get_shortname(name) for name in - team.name.split('
')]) + self.data.get_shortname(name) for name in team.name]) + team_name = '
'.join(team.name) label_max_length = self.page.get('label_length_limit', 0) if label_max_length: team_label = team_label[:label_max_length] + (team_label[label_max_length:] and '(...)') team_html = self.p_temp.get( 'MATCH_TEAM_LINK', - match.link, team.name, team_label) \ + match.link, team_name, team_label) \ if match.link is not None \ else self.p_temp.get( 'MATCH_TEAM_NON_LINK', - team.name, team_label) + team_name, team_label) rows += self.p_temp.get( 'MATCH_TEAM_ROW', ' '.join([ - 'winner' if team.name == match.winner else '', - 'loser' if team.name == match.loser else '' + 'winner' if match.winner in team.name else '', + 'loser' if match.loser in team.name else '' ]).strip(), team_html, self.p_temp.get( diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index ab742d4..e9854c5 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -58,9 +58,9 @@ class MatchInfo: teams[i].score = self.config['score'][score] try: team_no = int(score) - teams[i].name = self.teams[team_no-1][0] + teams[i].name = [self.teams[team_no-1][0]] except ValueError: - teams[i].name = score + teams[i].name = [score] teams_fetched = True else: teams[i].score = score @@ -77,8 +77,8 @@ class MatchInfo: row = self.database.fetch( self.config['database'], p_sql.MATCH_RESULTS, (self.config['table'], self.config['round'])) - teams[0].name = row[0] - teams[1].name = row[1] + teams[0].name = [row[0]] + teams[1].name = [row[1]] if fetch_scores: teams[0].score = row[3] + row[5] teams[1].score = row[4] + row[6] @@ -147,7 +147,7 @@ class MatchInfo: if isinstance(text, unicode)][0].strip(u'\xa0') for link in row.select('a[onmouseover]')] for i in range(0, 2): - teams[i].name = team_names[i] + teams[i].name = [team_names[i]] teams[i].score = scores[i] PlayoffLogger.get('matchinfo').info( 'HTML scores for match #%d: %s', @@ -158,9 +158,9 @@ class MatchInfo: for i in range(0, 2): match_teams = [] if isinstance(self.config['teams'][i], basestring): - teams[i].name = self.config['teams'][i] + teams[i].name = [self.config['teams'][i]] elif isinstance(self.config['teams'][i], list): - teams[i].name = '
'.join(self.config['teams'][i]) + teams[i].name = self.config['teams'][i] else: if 'winner' in self.config['teams'][i]: match_teams += [ @@ -176,11 +176,10 @@ class MatchInfo: for place in self.config['teams'][i]['place']] known_teams = [team for team in match_teams if team is not None] if len(known_teams) > 0: - teams[i].name = '
'.join([ - team if team is not None - else '??' for team in match_teams]) + teams[i].name = [team if team is not None + else '??' for team in match_teams] else: - teams[i].name = '' + teams[i].name = [''] PlayoffLogger.get('matchinfo').info( 'config scores for match #%d: %s', self.info.id, teams) @@ -341,13 +340,15 @@ class MatchInfo: else boards_played def __determine_outcome(self): - if (self.info.running == -1): - if self.info.teams[0].score > self.info.teams[1].score: - self.info.winner = self.info.teams[0].name - self.info.loser = self.info.teams[1].name - else: - self.info.loser = self.info.teams[0].name - self.info.winner = self.info.teams[1].name + if (len(self.info.teams[0].name) == 1) \ + and (len(self.info.teams[1].name) == 1): + if self.info.running == -1: + if self.info.teams[0].score > self.info.teams[1].score: + self.info.winner = self.info.teams[0].name[0] + self.info.loser = self.info.teams[1].name[0] + else: + self.info.loser = self.info.teams[0].name[0] + self.info.winner = self.info.teams[1].name[0] def __get_db_running_link(self, prefix, round_no): current_segment = int( -- cgit v1.2.3 From 03ab8b041179daa2ed75966a3c2255e239f8fde7 Mon Sep 17 00:00:00 2001 From: emkael Date: Mon, 1 Oct 2018 16:09:07 +0200 Subject: Explicitly counting known teams for match boxes --- jfr_playoff/dto.py | 1 + jfr_playoff/generator.py | 11 +++++++---- jfr_playoff/matchinfo.py | 18 ++++++++---------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/jfr_playoff/dto.py b/jfr_playoff/dto.py index ad70735..58b08c1 100644 --- a/jfr_playoff/dto.py +++ b/jfr_playoff/dto.py @@ -10,6 +10,7 @@ def coalesce(*arg): class Team(object): name = None score = 0.0 + known_teams = 0 def __init__(self): self.name = [] diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index a1b519e..f2a2c55 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -1,5 +1,6 @@ from datetime import datetime +from jfr_playoff.dto import coalesce from jfr_playoff.template import PlayoffTemplate from jfr_playoff.data import PlayoffData from jfr_playoff.logger import PlayoffLogger @@ -54,9 +55,11 @@ class PlayoffGenerator(object): rows = '' for team in match.teams: score_html = self.p_temp.get('MATCH_SCORE', team.score) + teams = [coalesce(name, '??') for name in team.name] team_label = ' / '.join([ - self.data.get_shortname(name) for name in team.name]) - team_name = '
'.join(team.name) + self.data.get_shortname(name) if name is not None else '??' for name in team.name]) \ + if team.known_teams > 0 else '' + team_name = '
'.join(teams) label_max_length = self.page.get('label_length_limit', 0) if label_max_length: team_label = team_label[:label_max_length] + (team_label[label_max_length:] and '(...)') @@ -70,8 +73,8 @@ class PlayoffGenerator(object): rows += self.p_temp.get( 'MATCH_TEAM_ROW', ' '.join([ - 'winner' if match.winner in team.name else '', - 'loser' if match.loser in team.name else '' + 'winner' if match.winner in teams else '', + 'loser' if match.loser in teams else '' ]).strip(), team_html, self.p_temp.get( diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index e9854c5..f7a156d 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -77,8 +77,9 @@ class MatchInfo: row = self.database.fetch( self.config['database'], p_sql.MATCH_RESULTS, (self.config['table'], self.config['round'])) - teams[0].name = [row[0]] - teams[1].name = [row[1]] + for i in range(0, 2): + teams[i].name = [row[i]] + teams[i].known_teams = 1 if fetch_scores: teams[0].score = row[3] + row[5] teams[1].score = row[4] + row[6] @@ -148,6 +149,7 @@ class MatchInfo: for link in row.select('a[onmouseover]')] for i in range(0, 2): teams[i].name = [team_names[i]] + teams[i].known_teams = 1 teams[i].score = scores[i] PlayoffLogger.get('matchinfo').info( 'HTML scores for match #%d: %s', @@ -174,12 +176,8 @@ class MatchInfo: match_teams += [ self.teams[place-1][0] for place in self.config['teams'][i]['place']] - known_teams = [team for team in match_teams if team is not None] - if len(known_teams) > 0: - teams[i].name = [team if team is not None - else '??' for team in match_teams] - else: - teams[i].name = [''] + teams[i].name = match_teams + teams[i].known_teams = len([team for team in match_teams if team is not None]) PlayoffLogger.get('matchinfo').info( 'config scores for match #%d: %s', self.info.id, teams) @@ -340,8 +338,8 @@ class MatchInfo: else boards_played def __determine_outcome(self): - if (len(self.info.teams[0].name) == 1) \ - and (len(self.info.teams[1].name) == 1): + if (self.info.teams[0].known_teams == 1) \ + and (self.info.teams[1].known_teams == 1): if self.info.running == -1: if self.info.teams[0].score > self.info.teams[1].score: self.info.winner = self.info.teams[0].name[0] -- cgit v1.2.3 From 62fe5244beb1a859b86aae86d784a86b30d86ca9 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 2 Oct 2018 12:41:31 +0200 Subject: Fetching info about possible outcomes of matches in progress --- jfr_playoff/dto.py | 4 ++++ jfr_playoff/matchinfo.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/jfr_playoff/dto.py b/jfr_playoff/dto.py index 58b08c1..b1a3a5c 100644 --- a/jfr_playoff/dto.py +++ b/jfr_playoff/dto.py @@ -9,11 +9,13 @@ def coalesce(*arg): class Team(object): name = None + possible_name = None score = 0.0 known_teams = 0 def __init__(self): self.name = [] + self.possible_name = [] def __unicode__(self): return u'%s (%.1f)' % (coalesce(self.name, ''), self.score) @@ -29,6 +31,8 @@ class Match(object): link = None winner = None loser = None + possible_winner = None + possible_loser = None winner_matches = None loser_matches = None diff --git a/jfr_playoff/matchinfo.py b/jfr_playoff/matchinfo.py index f7a156d..bb13ed9 100644 --- a/jfr_playoff/matchinfo.py +++ b/jfr_playoff/matchinfo.py @@ -159,6 +159,7 @@ class MatchInfo: def __get_config_teams(self, teams): for i in range(0, 2): match_teams = [] + possible_teams = [] if isinstance(self.config['teams'][i], basestring): teams[i].name = [self.config['teams'][i]] elif isinstance(self.config['teams'][i], list): @@ -168,15 +169,22 @@ class MatchInfo: match_teams += [ MatchInfo.matches[winner_match].winner for winner_match in self.config['teams'][i]['winner']] + possible_teams += [ + MatchInfo.matches[winner_match].possible_winner + for winner_match in self.config['teams'][i]['winner']] if 'loser' in self.config['teams'][i]: match_teams += [ MatchInfo.matches[loser_match].loser for loser_match in self.config['teams'][i]['loser']] + possible_teams += [ + MatchInfo.matches[loser_match].possible_loser + for loser_match in self.config['teams'][i]['loser']] if 'place' in self.config['teams'][i]: match_teams += [ self.teams[place-1][0] for place in self.config['teams'][i]['place']] teams[i].name = match_teams + teams[i].possible_name = possible_teams teams[i].known_teams = len([team for team in match_teams if team is not None]) PlayoffLogger.get('matchinfo').info( 'config scores for match #%d: %s', @@ -347,6 +355,13 @@ class MatchInfo: else: self.info.loser = self.info.teams[0].name[0] self.info.winner = self.info.teams[1].name[0] + elif self.info.running > 0: + if self.info.teams[0].score > self.info.teams[1].score: + self.info.possible_winner = self.info.teams[0].name[0] + self.info.possible_loser = self.info.teams[1].name[0] + elif self.info.teams[0].score < self.info.teams[1].score: + self.info.possible_loser = self.info.teams[0].name[0] + self.info.possible_winner = self.info.teams[1].name[0] def __get_db_running_link(self, prefix, round_no): current_segment = int( -- cgit v1.2.3 From 6119175f65c6bc12771a968cd72e6c8179848f78 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 2 Oct 2018 12:43:11 +0200 Subject: Templates and strings for new team label rendering method --- jfr_playoff/generator.py | 6 ++++++ jfr_playoff/i18n.py | 4 +++- jfr_playoff/template.py | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index f2a2c55..fab6d0e 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -51,6 +51,12 @@ class PlayoffGenerator(object): 'PAGE_BODY_FOOTER', datetime.now().strftime('%Y-%m-%d o %H:%M:%S')))) + def __get_team_label(self, team_name, template='MATCH_TEAM_LABEL'): + if not self.page.get('predict_teams', None): + # override template if team predictions are not enabled + template = 'MATCH_TEAM_LABEL' + return self.p_temp.get(template, team_name) + def get_match_table(self, match): rows = '' for team in match.teams: diff --git a/jfr_playoff/i18n.py b/jfr_playoff/i18n.py index c4134a9..63576db 100644 --- a/jfr_playoff/i18n.py +++ b/jfr_playoff/i18n.py @@ -11,7 +11,9 @@ PLAYOFF_I18N_DEFAULTS = { 'STANDINGS_TEAM': 'drużyna', 'STANDINGS_CAPTIONS': 'legenda', 'FOOTER_GENERATED': 'strona wygenerowana', - 'SWISS_DEFAULT_LABEL': 'Turniej o %d. miejsce' + 'SWISS_DEFAULT_LABEL': 'Turniej o %d. miejsce', + 'DETERMINED_TEAMS': 'Drużyny z pewnym miejscem w tej fazie:', + 'POSSIBLE_TEAMS': 'Drużyny z trwających meczów poprzedniej fazy:' } class PlayoffI18N(object): diff --git a/jfr_playoff/template.py b/jfr_playoff/template.py index 70c179b..5845498 100644 --- a/jfr_playoff/template.py +++ b/jfr_playoff/template.py @@ -24,6 +24,14 @@ class PlayoffTemplateStrings(object):  %.1f  ''' + MATCH_TEAM_LABEL = '%s' + + MATCH_PREDICTED_TEAM_LABEL = '%s' + + MATCH_TEAM_LIST_HEADER = '{{DETERMINED_TEAMS}}' + + MATCH_POSSIBLE_TEAM_LIST_HEADER = '{{POSSIBLE_TEAMS}}' + MATCH_TEAM_LINK = ''' %s ''' -- cgit v1.2.3 From 79c281bb47d08f1fd1be04b1d7d58dfd8c672bc5 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 2 Oct 2018 13:31:02 +0200 Subject: New team label rendering method, including outcome preditctions --- jfr_playoff/generator.py | 73 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index fab6d0e..7895a73 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -60,15 +60,68 @@ class PlayoffGenerator(object): def get_match_table(self, match): rows = '' for team in match.teams: + # the easy part: team score cell score_html = self.p_temp.get('MATCH_SCORE', team.score) - teams = [coalesce(name, '??') for name in team.name] - team_label = ' / '.join([ - self.data.get_shortname(name) if name is not None else '??' for name in team.name]) \ - if team.known_teams > 0 else '' - team_name = '
'.join(teams) - label_max_length = self.page.get('label_length_limit', 0) - if label_max_length: - team_label = team_label[:label_max_length] + (team_label[label_max_length:] and '(...)') + # the hard part begins here. + team_label = [] # label is what's shown in the table cell + label_separator = ' / ' + team_name = [] # name is what's shown in the tooltip + name_separator = '
' + name_prefix = '  ' # prefix (indent) for team names in the tooltip + if (team.known_teams == 0) and not self.page.get('predict_teams', False): + # we've got no teams eligible for the match and the prediction option is disabled + team_label = '' + team_name = '' + else: + # predicted teams are not in team.name, they're in tem.possible_name so corresponding spots in team.name are empty + is_label_predicted = [name is None for name in team.name] + # fetch labels (shortnames) for teams in both lists + labels = [self.data.get_shortname(name) if name else None for name in team.name] + predicted_labels = [self.data.get_shortname(name) if name else None for name in team.possible_name] + for l in range(0, len(labels)): + if labels[l] is None: + if self.page.get('predict_teams', False) and (len(predicted_labels) > l): + # fill team labels with either predictions... + labels[l] = predicted_labels[l] + else: + # ...or empty placeholders + labels[l] = '??' + # count how many teams are eligible (how many non-predicted teams are there) + known_teams = len(is_label_predicted) - sum(is_label_predicted) + # sort labels to move eligible teams in front of predicted teams + # TODO: should this be optional? + labels = [label for i, label in enumerate(labels) if not is_label_predicted[i]] \ + + [label for i, label in enumerate(labels) if is_label_predicted[i]] + if len([label for label in labels if label is not None]): + # we have at least one known/predicted team + for l in range(0, len(labels)): + # fill any remaining empty labels (i.e. these which had empty predictions available) with placeholders + labels[l] = coalesce(labels[l], '??') + # concatenate labels, assigning appropriate classes to predicted teams + team_label.append(self.__get_team_label( + labels[l], + 'MATCH_PREDICTED_TEAM_LABEL' if l >= known_teams else 'MATCH_TEAM_LABEL')) + # team names for tooltip + for name in team.name: + if name: + # every non-empty name gets some indentation + team_name.append(name_prefix + name) + if self.page.get('predict_teams', False): + # remember where the list of eligible teams ends + known_teams = len(team_name) + for name in team.possible_name: + # append predicted team names, with indentation as well + if name: + team_name.append(name_prefix + name) + if len(team_name) != known_teams: + # we've added some predicted team names, so we add a header + team_name.insert(known_teams, self.p_temp.get('MATCH_POSSIBLE_TEAM_LIST_HEADER')) + if (len(team_label) > 1) and (match.running == 0): + # and we add a header for matches that haven't started yet and have multiple options for teams + team_name.insert(0, self.p_temp.get('MATCH_TEAM_LIST_HEADER')) + # glue it all together + team_label = label_separator.join(team_label) + team_name = name_separator.join(team_name) team_html = self.p_temp.get( 'MATCH_TEAM_LINK', match.link, team_name, team_label) \ @@ -79,8 +132,8 @@ class PlayoffGenerator(object): rows += self.p_temp.get( 'MATCH_TEAM_ROW', ' '.join([ - 'winner' if match.winner in teams else '', - 'loser' if match.loser in teams else '' + 'winner' if (match.winner is not None) and (match.winner in team.name) else '', + 'loser' if (match.loser is not None) and (match.loser in team.name) else '' ]).strip(), team_html, self.p_temp.get( -- cgit v1.2.3 From b2a6d843d69edc40c8f7782e47db28ca89baf77e Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 2 Oct 2018 13:32:08 +0200 Subject: Bringing back label shortening, this time compatible with separate team labels --- jfr_playoff/generator.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 7895a73..beaabd7 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -57,6 +57,30 @@ class PlayoffGenerator(object): template = 'MATCH_TEAM_LABEL' return self.p_temp.get(template, team_name) + def __shorten_labels(self, labels, limit, separator, ellipsis): + if limit > 0: + current_length = 0 + shortened = [] + for l in range(0, len(labels)): + if current_length + len(labels[l]) > limit: + # current label won't fit within limit, shorten it and stop + shortened.append(labels[l][0:limit-current_length] + ellipsis) + break + else: + # current label fits, add it to output + shortened.append(labels[l]) + current_length += len(labels[l]) + if l < len(labels) - 1: + # if it's not the last label, separator will be added + # if it was the last label, next condition won't run and ellipsis won't be added + current_length += len(separator) + if current_length > limit: + # if separator puts us over the limit, add ellipsis and stop + shortened.append(ellipsis) + break + labels = shortened + return labels + def get_match_table(self, match): rows = '' for team in match.teams: @@ -97,6 +121,9 @@ class PlayoffGenerator(object): for l in range(0, len(labels)): # fill any remaining empty labels (i.e. these which had empty predictions available) with placeholders labels[l] = coalesce(labels[l], '??') + # shorten concatenated label to specified combined length + labels = self.__shorten_labels(labels, self.page.get('label_length_limit', 0), label_separator, '(...)') + for l in range(0, len(labels)): # concatenate labels, assigning appropriate classes to predicted teams team_label.append(self.__get_team_label( labels[l], -- cgit v1.2.3 From 43d8243888590debd2d2efcdd5be3f415cfa1756 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 2 Oct 2018 13:33:12 +0200 Subject: Documentation for team name predictions Fixes #7 --- CONFIG.md | 1 + jfr_playoff/generator.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CONFIG.md b/CONFIG.md index 3a26f81..471b190 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -26,6 +26,7 @@ Konfiguracja składa się, po kolei, z: + `"width"` i `"height"` - wymiary (w pikselach) miejsca rezerwowanego dla każdego meczu w widoku drabinki (`"width"` bezpośrednio wpływa na rozmieszczanie kolumn, wewnątrz każdej z kolumn mecze rozmieszczane są równomiernie, w zależnie od ich liczby) + `"margin"` - odstęp między w/w miejscem (minimalny - jak widać, w przypadku mniejszej liczby meczów w fazie, odstępy się dopasują) + `"label_length_limit"` - maksymalna liczba znaków wyświetlanych jako skrócona nazwa drużyn(y) w schemacie (`0` lub brak wartości oznacza brak limitu) + + `"predict_teams"` - flaga, jeśli włączona (`1`), w kolejnej fazie wypełniane są nazwy drużyn prowadzących/przegrywających w trwających meczach tak, jakby mecz miał się skończyć aktualnym wynikiem (etykiety takich drużyn mają nadaną osobną klasę CSS) - sekcji `"canvas"`: ustawień rysowania linii + `"winner_h_offset"`, `"winner_v_offset"` - marginesy (poziomy i pionowy) rysowania linii zwycięzców (odpowiednio: pionowych i poziomych, względem środka obszaru) + `"loser_h_offset"`, `"loser_v_offset"` - analogiczne marginesy rysowania linii przegranych diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index beaabd7..2028060 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -87,6 +87,7 @@ class PlayoffGenerator(object): # the easy part: team score cell score_html = self.p_temp.get('MATCH_SCORE', team.score) # the hard part begins here. + # TODO: should separators and ellipsis indicators be configurable? team_label = [] # label is what's shown in the table cell label_separator = ' / ' team_name = [] # name is what's shown in the tooltip -- cgit v1.2.3 From f235f596c5aa4525f0d64bfa1cfc96cf57a778d5 Mon Sep 17 00:00:00 2001 From: emkael Date: Tue, 2 Oct 2018 13:35:26 +0200 Subject: Updating branch information --- BRANCHES.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BRANCHES.txt b/BRANCHES.txt index ee53fe4..17f5c26 100644 --- a/BRANCHES.txt +++ b/BRANCHES.txt @@ -23,3 +23,7 @@ Względem ostatniego sezonu - [devel] - możliwość wyświetlania elementów grafu dla pozycji początkowych i pozycji końcowych - możliwość dowolnego pozycjonowania meczów (zarówno w pionie w ramach fazy, jak i o zupełnie dowolnych współrzędnych) + +[next-round-prognosis] + - [devel] + - wypełnianie wyszarszonym kolorem nazw drużyn następnej rundy, gdy mecz obecnej rundy już trwa -- cgit v1.2.3 From 0ae3b4c385d293b1ac8553717c30e4f7222a743c Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 10 Oct 2018 00:00:37 +0200 Subject: Parameterization of team box label settings --- CONFIG.md | 10 ++++++++-- jfr_playoff/generator.py | 24 +++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index 471b190..f6d55c5 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -25,8 +25,14 @@ Konfiguracja składa się, po kolei, z: + `"refresh"` - parametr odświeżania strony drabinki: `0` = wyłączone, liczba naturalna = interwał odświeżania, w sekundach + `"width"` i `"height"` - wymiary (w pikselach) miejsca rezerwowanego dla każdego meczu w widoku drabinki (`"width"` bezpośrednio wpływa na rozmieszczanie kolumn, wewnątrz każdej z kolumn mecze rozmieszczane są równomiernie, w zależnie od ich liczby) + `"margin"` - odstęp między w/w miejscem (minimalny - jak widać, w przypadku mniejszej liczby meczów w fazie, odstępy się dopasują) - + `"label_length_limit"` - maksymalna liczba znaków wyświetlanych jako skrócona nazwa drużyn(y) w schemacie (`0` lub brak wartości oznacza brak limitu) - + `"predict_teams"` - flaga, jeśli włączona (`1`), w kolejnej fazie wypełniane są nazwy drużyn prowadzących/przegrywających w trwających meczach tak, jakby mecz miał się skończyć aktualnym wynikiem (etykiety takich drużyn mają nadaną osobną klasę CSS) + + słownik `"team_boxes"` przechowuje opcjonalne ustawienia wyświetlania nazw teamów: + * `"label_length_limit"` - maksymalna liczba znaków wyświetlanych jako skrócona nazwa drużyn(y) w schemacie (domyślnie `0` = brak limitu) + * `"predict_teams"` - flaga, jeśli włączona (`1`), w kolejnej fazie wypełniane są nazwy drużyn prowadzących/przegrywających w trwających meczach tak, jakby mecz miał się skończyć aktualnym wynikiem (etykiety takich drużyn mają nadaną osobną klasę CSS) + * `"label_separator"` - ciąg rozdzielający skrócone nazwy drużyn wyświetlane na schemacie (domyślnie ` / `) + * `"label_placeholder"` - ciąg wyświetlany w miejsce nieznanej drużyny (domyślnie `??`) + * `"label_ellipsis"` - ciąg wyświetlany na końcu skróconej etykiety teamów, gdy ustawienie `label_length_limit` ją skróciło (domyślnie `(...)`) + * `"name_separator"` - ciąg rozdzielający pełne nazwy teamów w etykiecie po najechaniu na skrócone nazwy w schemacie (domyślnie `
`) + * `"name_prefix"` - ciąg poprzedzający każdą pełną nazwę teamów w etykiecie po najechaniu (domyślnie wcięcie `  `) - sekcji `"canvas"`: ustawień rysowania linii + `"winner_h_offset"`, `"winner_v_offset"` - marginesy (poziomy i pionowy) rysowania linii zwycięzców (odpowiednio: pionowych i poziomych, względem środka obszaru) + `"loser_h_offset"`, `"loser_v_offset"` - analogiczne marginesy rysowania linii przegranych diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 2028060..48a2eac 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -12,6 +12,7 @@ class PlayoffGenerator(object): self.page = settings.get('page') PlayoffLogger.get('generator').info( 'page settings: %s', self.page) + self.team_box_settings = self.page.get('team_boxes', {}) self.canvas = {} if settings.has_section('canvas'): self.canvas = settings.get('canvas') @@ -52,7 +53,7 @@ class PlayoffGenerator(object): datetime.now().strftime('%Y-%m-%d o %H:%M:%S')))) def __get_team_label(self, team_name, template='MATCH_TEAM_LABEL'): - if not self.page.get('predict_teams', None): + if not self.team_box_settings.get('predict_teams', None): # override template if team predictions are not enabled template = 'MATCH_TEAM_LABEL' return self.p_temp.get(template, team_name) @@ -87,13 +88,14 @@ class PlayoffGenerator(object): # the easy part: team score cell score_html = self.p_temp.get('MATCH_SCORE', team.score) # the hard part begins here. - # TODO: should separators and ellipsis indicators be configurable? team_label = [] # label is what's shown in the table cell - label_separator = ' / ' + label_separator = self.team_box_settings.get('label_separator', ' / ') + label_placeholder = self.team_box_settings.get('label_placeholder', '??') + label_ellipsis = self.team_box_settings.get('label_ellipsis', '(...)') team_name = [] # name is what's shown in the tooltip - name_separator = '
' - name_prefix = '  ' # prefix (indent) for team names in the tooltip - if (team.known_teams == 0) and not self.page.get('predict_teams', False): + name_separator = self.team_box_settings.get('name_separator', '
') + name_prefix = self.team_box_settings.get('name_prefix', '  ') # prefix (indent) for team names in the tooltip + if (team.known_teams == 0) and not self.team_box_settings.get('predict_teams', False): # we've got no teams eligible for the match and the prediction option is disabled team_label = '' team_name = '' @@ -105,12 +107,12 @@ class PlayoffGenerator(object): predicted_labels = [self.data.get_shortname(name) if name else None for name in team.possible_name] for l in range(0, len(labels)): if labels[l] is None: - if self.page.get('predict_teams', False) and (len(predicted_labels) > l): + if self.team_box_settings.get('predict_teams', False) and (len(predicted_labels) > l): # fill team labels with either predictions... labels[l] = predicted_labels[l] else: # ...or empty placeholders - labels[l] = '??' + labels[l] = label_placeholder # count how many teams are eligible (how many non-predicted teams are there) known_teams = len(is_label_predicted) - sum(is_label_predicted) # sort labels to move eligible teams in front of predicted teams @@ -121,9 +123,9 @@ class PlayoffGenerator(object): # we have at least one known/predicted team for l in range(0, len(labels)): # fill any remaining empty labels (i.e. these which had empty predictions available) with placeholders - labels[l] = coalesce(labels[l], '??') + labels[l] = coalesce(labels[l], label_placeholder) # shorten concatenated label to specified combined length - labels = self.__shorten_labels(labels, self.page.get('label_length_limit', 0), label_separator, '(...)') + labels = self.__shorten_labels(labels, self.team_box_settings.get('label_length_limit', 0), label_separator, label_ellipsis) for l in range(0, len(labels)): # concatenate labels, assigning appropriate classes to predicted teams team_label.append(self.__get_team_label( @@ -134,7 +136,7 @@ class PlayoffGenerator(object): if name: # every non-empty name gets some indentation team_name.append(name_prefix + name) - if self.page.get('predict_teams', False): + if self.team_box_settings.get('predict_teams', False): # remember where the list of eligible teams ends known_teams = len(team_name) for name in team.possible_name: -- cgit v1.2.3 From 13e1272ad6daf785671270b38cccbff3afb91716 Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 10 Oct 2018 00:57:58 +0200 Subject: Logging messages for team label/name generator --- jfr_playoff/generator.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 48a2eac..64bdeaa 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -85,8 +85,12 @@ class PlayoffGenerator(object): def get_match_table(self, match): rows = '' for team in match.teams: + PlayoffLogger.get('generator').info( + 'generating HTML for team object: %s', team) # the easy part: team score cell score_html = self.p_temp.get('MATCH_SCORE', team.score) + PlayoffLogger.get('generator').info( + 'score HTML for team object: %s', score_html.strip()) # the hard part begins here. team_label = [] # label is what's shown in the table cell label_separator = self.team_box_settings.get('label_separator', ' / ') @@ -96,6 +100,7 @@ class PlayoffGenerator(object): name_separator = self.team_box_settings.get('name_separator', '
') name_prefix = self.team_box_settings.get('name_prefix', '  ') # prefix (indent) for team names in the tooltip if (team.known_teams == 0) and not self.team_box_settings.get('predict_teams', False): + PlayoffLogger.get('generator').info('no eligible teams and predictions are disabled') # we've got no teams eligible for the match and the prediction option is disabled team_label = '' team_name = '' @@ -104,7 +109,9 @@ class PlayoffGenerator(object): is_label_predicted = [name is None for name in team.name] # fetch labels (shortnames) for teams in both lists labels = [self.data.get_shortname(name) if name else None for name in team.name] + PlayoffLogger.get('generator').info('eligible team labels: %s', labels) predicted_labels = [self.data.get_shortname(name) if name else None for name in team.possible_name] + PlayoffLogger.get('generator').info('predicted team labels: %s', predicted_labels) for l in range(0, len(labels)): if labels[l] is None: if self.team_box_settings.get('predict_teams', False) and (len(predicted_labels) > l): @@ -115,10 +122,12 @@ class PlayoffGenerator(object): labels[l] = label_placeholder # count how many teams are eligible (how many non-predicted teams are there) known_teams = len(is_label_predicted) - sum(is_label_predicted) + PlayoffLogger.get('generator').info('detected %d known teams, predicted mask: %s', known_teams, is_label_predicted) # sort labels to move eligible teams in front of predicted teams # TODO: should this be optional? labels = [label for i, label in enumerate(labels) if not is_label_predicted[i]] \ + [label for i, label in enumerate(labels) if is_label_predicted[i]] + PlayoffLogger.get('generator').info('team labels: %s', labels) if len([label for label in labels if label is not None]): # we have at least one known/predicted team for l in range(0, len(labels)): @@ -126,6 +135,7 @@ class PlayoffGenerator(object): labels[l] = coalesce(labels[l], label_placeholder) # shorten concatenated label to specified combined length labels = self.__shorten_labels(labels, self.team_box_settings.get('label_length_limit', 0), label_separator, label_ellipsis) + PlayoffLogger.get('generator').info('shortened team labels: %s', labels) for l in range(0, len(labels)): # concatenate labels, assigning appropriate classes to predicted teams team_label.append(self.__get_team_label( @@ -151,7 +161,9 @@ class PlayoffGenerator(object): team_name.insert(0, self.p_temp.get('MATCH_TEAM_LIST_HEADER')) # glue it all together team_label = label_separator.join(team_label) + PlayoffLogger.get('generator').info('output teams label HTML: %s', team_label) team_name = name_separator.join(team_name) + PlayoffLogger.get('generator').info('output teams name HTML: %s', team_name) team_html = self.p_temp.get( 'MATCH_TEAM_LINK', match.link, team_name, team_label) \ -- cgit v1.2.3 From 8181571f14486be1d81dde08e8c7a088241f9fb7 Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 10 Oct 2018 01:03:02 +0200 Subject: Sorting eligible teams in front of predicted teams is now optional --- CONFIG.md | 1 + jfr_playoff/generator.py | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CONFIG.md b/CONFIG.md index f6d55c5..eec5ed1 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -33,6 +33,7 @@ Konfiguracja składa się, po kolei, z: * `"label_ellipsis"` - ciąg wyświetlany na końcu skróconej etykiety teamów, gdy ustawienie `label_length_limit` ją skróciło (domyślnie `(...)`) * `"name_separator"` - ciąg rozdzielający pełne nazwy teamów w etykiecie po najechaniu na skrócone nazwy w schemacie (domyślnie `
`) * `"name_prefix"` - ciąg poprzedzający każdą pełną nazwę teamów w etykiecie po najechaniu (domyślnie wcięcie `  `) + * `"sort_eligible_first"` - flaga włączająca wyświetlanie teamów zakwalifikowanych do danej fazy (tj. z zakończonym meczem bieżącej fazy) przed teamami z trwających meczów (domyślnie włączona) - sekcji `"canvas"`: ustawień rysowania linii + `"winner_h_offset"`, `"winner_v_offset"` - marginesy (poziomy i pionowy) rysowania linii zwycięzców (odpowiednio: pionowych i poziomych, względem środka obszaru) + `"loser_h_offset"`, `"loser_v_offset"` - analogiczne marginesy rysowania linii przegranych diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index 64bdeaa..c78d5cb 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -122,11 +122,11 @@ class PlayoffGenerator(object): labels[l] = label_placeholder # count how many teams are eligible (how many non-predicted teams are there) known_teams = len(is_label_predicted) - sum(is_label_predicted) - PlayoffLogger.get('generator').info('detected %d known teams, predicted mask: %s', known_teams, is_label_predicted) - # sort labels to move eligible teams in front of predicted teams - # TODO: should this be optional? - labels = [label for i, label in enumerate(labels) if not is_label_predicted[i]] \ - + [label for i, label in enumerate(labels) if is_label_predicted[i]] + PlayoffLogger.get('generator').info('detected %d known team(s), predicted mask: %s', known_teams, is_label_predicted) + if self.team_box_settings.get('sort_eligible_first', True): + # sort labels to move eligible teams in front of predicted teams + labels = [label for i, label in enumerate(labels) if not is_label_predicted[i]] \ + + [label for i, label in enumerate(labels) if is_label_predicted[i]] PlayoffLogger.get('generator').info('team labels: %s', labels) if len([label for label in labels if label is not None]): # we have at least one known/predicted team @@ -138,9 +138,14 @@ class PlayoffGenerator(object): PlayoffLogger.get('generator').info('shortened team labels: %s', labels) for l in range(0, len(labels)): # concatenate labels, assigning appropriate classes to predicted teams - team_label.append(self.__get_team_label( - labels[l], - 'MATCH_PREDICTED_TEAM_LABEL' if l >= known_teams else 'MATCH_TEAM_LABEL')) + if self.team_box_settings.get('sort_eligible_first', True): + team_label.append(self.__get_team_label( + labels[l], + 'MATCH_PREDICTED_TEAM_LABEL' if l >= known_teams else 'MATCH_TEAM_LABEL')) + else: + team_label.append(self.__get_team_label( + labels[l], + 'MATCH_PREDICTED_TEAM_LABEL' if is_label_predicted[l] else 'MATCH_TEAM_LABEL')) # team names for tooltip for name in team.name: if name: -- cgit v1.2.3 From ef9a1565fba727d05d4ebf91ef4a63f01b83f4bf Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 10 Oct 2018 01:09:05 +0200 Subject: Backwards compatibility with legacy config structure --- jfr_playoff/generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jfr_playoff/generator.py b/jfr_playoff/generator.py index c78d5cb..898e5ed 100644 --- a/jfr_playoff/generator.py +++ b/jfr_playoff/generator.py @@ -95,6 +95,7 @@ class PlayoffGenerator(object): team_label = [] # label is what's shown in the table cell label_separator = self.team_box_settings.get('label_separator', ' / ') label_placeholder = self.team_box_settings.get('label_placeholder', '??') + label_length_limit = self.team_box_settings.get('label_length_limit', self.page.get('label_length_limit', 0)) label_ellipsis = self.team_box_settings.get('label_ellipsis', '(...)') team_name = [] # name is what's shown in the tooltip name_separator = self.team_box_settings.get('name_separator', '
') @@ -134,7 +135,7 @@ class PlayoffGenerator(object): # fill any remaining empty labels (i.e. these which had empty predictions available) with placeholders labels[l] = coalesce(labels[l], label_placeholder) # shorten concatenated label to specified combined length - labels = self.__shorten_labels(labels, self.team_box_settings.get('label_length_limit', 0), label_separator, label_ellipsis) + labels = self.__shorten_labels(labels, label_length_limit, label_separator, label_ellipsis) PlayoffLogger.get('generator').info('shortened team labels: %s', labels) for l in range(0, len(labels)): # concatenate labels, assigning appropriate classes to predicted teams -- cgit v1.2.3 From 29fc58378a33628cc73fa9b897d844b652578638 Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 17 Oct 2018 19:52:24 +0200 Subject: Version number bump --- .version | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.version b/.version index a27e39d..3f47e42 100644 --- a/.version +++ b/.version @@ -1,8 +1,8 @@ # UTF-8 VSVersionInfo( ffi=FixedFileInfo( - filevers=(1, 2, 0, 0), - prodvers=(1, 2, 0, 0), + filevers=(1, 2, 1, 0), + prodvers=(1, 2, 1, 0), # Contains a bitmask that specifies the valid bits 'flags' mask=0x3f, # Contains a bitmask that specifies the Boolean attributes of the file. @@ -26,10 +26,10 @@ VSVersionInfo( u'040904b0', # 0x0409(1033)= English, 0x04b0(1200)= UTF-8 [StringStruct(u'CompanyName', u'emkael.info'), StringStruct(u'ProductName', u'teamy_playoff'), - StringStruct(u'ProductVersion', u'1, 2, 0, 0'), + StringStruct(u'ProductVersion', u'1, 2, 1, 0'), StringStruct(u'InternalName', u'teamy_playoff'), StringStruct(u'OriginalFilename', u'playoff.exe'), - StringStruct(u'FileVersion', u'1, 2, 0, 0'), + StringStruct(u'FileVersion', u'1, 2, 1, 0'), StringStruct( u'FileDescription', u'Play-off visualisation for JFR Teamy events'), -- cgit v1.2.3 From 9a2db36e92d12f2724801de3618e2794579ac302 Mon Sep 17 00:00:00 2001 From: emkael Date: Wed, 17 Oct 2018 20:04:23 +0200 Subject: Removing branch information --- BRANCHES.txt | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 BRANCHES.txt diff --git a/BRANCHES.txt b/BRANCHES.txt deleted file mode 100644 index 17f5c26..0000000 --- a/BRANCHES.txt +++ /dev/null @@ -1,29 +0,0 @@ -Względem ostatniego sezonu - -[master] [v1.1.2]: - - oznaczenia (style) w tabeli końcowej - -[bugfixes]: - - poprawki wymiarów (całego obszaru rysowania oraz odstępów między obszarami poszczególnych meczów) - -[i18n]: - - nowy silnik szablonów - - tłumaczenia - -[devel]: - - [i18n] - - [bugfixes] - - obszerne komunikaty diagnostyczne - - poprawki z Sopotu: - + skracanie wyświetlania długich nazw teamów - + obsługa meczów jednosegmentowych - - nielinkowanie do segmentów, które nie wysyłają wyników na żywo - -[position-boxes]: - - [devel] - - możliwość wyświetlania elementów grafu dla pozycji początkowych i pozycji końcowych - - możliwość dowolnego pozycjonowania meczów (zarówno w pionie w ramach fazy, jak i o zupełnie dowolnych współrzędnych) - -[next-round-prognosis] - - [devel] - - wypełnianie wyszarszonym kolorem nazw drużyn następnej rundy, gdy mecz obecnej rundy już trwa -- cgit v1.2.3