diff options
author | emkael <emkael@tlen.pl> | 2017-02-22 14:25:36 +0100 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2017-02-22 14:25:36 +0100 |
commit | f118c0f3704fa07a33543ee2aa018f16ac993b5a (patch) | |
tree | fba2537a34740a72875e3713c187adbbe52fc003 |
Initial commit
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | playoff.js | 137 | ||||
-rw-r--r-- | playoff.py | 205 | ||||
-rw-r--r-- | playoff/__init__.py | 0 | ||||
-rw-r--r-- | playoff/sql.py | 23 | ||||
-rw-r--r-- | playoff/template.py | 116 |
6 files changed, 483 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8b70d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.json diff --git a/playoff.js b/playoff.js new file mode 100644 index 0000000..9060c6d --- /dev/null +++ b/playoff.js @@ -0,0 +1,137 @@ +var playoff = { + + settings: { + 'winner_h_offset': 10, + 'loser_h_offset': 20, + 'winner_v_offset': -4, + 'loser_v_offset': 4, + 'loser_colour': '#ff0000', + 'winner_colour': '#00ff00' + }, + + drawLine: function(ctx, line) { + ctx.beginPath(); + ctx.moveTo(line[0], line[1]); + ctx.lineTo(line[2], line[3]); + ctx.stroke(); + }, + + run: function() { + var boxes = document.getElementsByClassName('playoff_matchbox'); + var lines = { + 'winner': {}, + 'loser': {} + }; + var boxes_idx = {}; + for (var b = 0; b < boxes.length; b++) { + var id = boxes[b].getAttribute('data-id'); + boxes_idx[id] = boxes[b]; + for (var attr in lines) { + var value = boxes[b].getAttribute('data-' + attr); + if (value) { + if (!lines[attr][value]) { + lines[attr][value] = []; + } + lines[attr][value].push(id); + } + } + } + var canvas = document.getElementById('playoff_canvas'); + 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]; + for (var f = 0; f < from.length; f++) { + var box = boxes_idx[from[f]]; + var line = [ + parseInt(box.style.left) + parseInt(box.clientWidth), + parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset'], + parseInt(box.style.left) + parseInt(box.clientWidth) + this.settings[type + '_h_offset'], + parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset'] + ]; + horizontal_from.push(line); + for (var l in horizontal_from) { + if (horizontal_from[l][2] < line[2]) { + horizontal_from[l][2] = line[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]; + } + } + } + var horizontal_to = []; + var vertical_to = [canvas.width, canvas.height, canvas.width, 0]; + for (var t = 0; t < to.length; t++) { + var box = boxes_idx[to[t]]; + var line = [ + parseInt(box.style.left), + parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset'], + parseInt(box.style.left) - this.settings[type + '_h_offset'], + parseInt(box.style.top) + 0.5 * parseInt(box.clientHeight) + this.settings[type + '_v_offset'] + ]; + horizontal_to.push(line); + for (var l in horizontal_to) { + if (horizontal_to[l][2] > line[2]) { + horizontal_to[l][2] = line[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]; + } + } + } + var midpoints = [ + [ + (vertical_from[0] + vertical_from[2]) / 2, + (vertical_from[1] + vertical_from[3]) / 2 + ], + [ + (vertical_from[0] + vertical_from[2] + vertical_to[0] + vertical_to[2]) / 4, + (vertical_from[1] + vertical_from[3]) / 2 + ], + [ + (vertical_from[0] + vertical_from[2] + vertical_to[0] + vertical_to[2]) / 4, + (vertical_to[1] + vertical_to[3]) / 2 + ], + [ + (vertical_to[0] + vertical_to[2]) / 2, + (vertical_to[1] + vertical_to[3]) / 2 + ] + ] + for (var l in horizontal_from) { + this.drawLine(ctx, horizontal_from[l]); + } + this.drawLine(ctx, vertical_from); + for (var l in horizontal_to) { + this.drawLine(ctx, horizontal_to[l]); + } + this.drawLine(ctx, vertical_to); + for (var m = 0; m < midpoints.length-1; m++) { + this.drawLine(ctx, [ + midpoints[m][0], midpoints[m][1], midpoints[m+1][0], midpoints[m+1][1] + ]); + } + } + } + } + +} + +playoff.run(); diff --git a/playoff.py b/playoff.py new file mode 100644 index 0000000..e2243d8 --- /dev/null +++ b/playoff.py @@ -0,0 +1,205 @@ +import json, os, shutil, sys +import mysql.connector +from datetime import datetime +from playoff import sql as p_sql +from playoff import template as p_temp + +settings = json.load(open(sys.argv[1])) +teams = settings['teams'] +leaderboard = [None] * len(teams) + +database = mysql.connector.connect( + user=settings['database']['user'], + password=settings['database']['pass'], + host=settings['database']['host'], + port=settings['database']['port'] +) +db_cursor = database.cursor(buffered=True) + +def db_fetch(db, sql, params): + db_cursor.execute(sql.replace('#db#', db), params) + row = db_cursor.fetchone() + return row + +def get_shortname(fullname): + for team in settings['teams']: + if team[0] == fullname: + return team[1] + return fullname + +def get_match_table(match): + rows = '' + for team in match.teams: + rows += p_temp.MATCH_TEAM_ROW % ( + team.name, + ' / '.join([get_shortname(name) for name in team.name.split('<br />')]), + team.score + ) + html = p_temp.MATCH_TABLE.decode('utf8') % ( + int(settings['page']['width'] * 0.75), + int(settings['page']['width'] * 0.25), + rows + ) + if match.running > 0: + html += p_temp.MATCH_RUNNING % (match.link, match.running) + return html + +def get_match_grid(grid, matches, width, height): + grid_boxes = '' + col_no = 0 + for column in grid: + grid_x = col_no * (settings['page']['width'] + settings['page']['margin']) + grid_header = p_temp.MATCH_GRID_PHASE_RUNNING if len([match for match in column if matches[match].running > 0]) > 0 else p_temp.MATCH_GRID_PHASE + grid_boxes += grid_header % ( + settings['phases'][col_no]['link'], + settings['page']['width'], + grid_x, + settings['phases'][col_no]['title'] + ) + row_no = 0 + column_height = height / len(column) + for match in column: + grid_y = int(row_no * column_height + 0.5 * (column_height - settings['page']['height'])) + grid_boxes += p_temp.MATCH_BOX % ( + grid_x, grid_y, + match, + ' '.join([str(m) for m in matches[match].winner_matches]) if matches[match].winner_matches is not None else '', + ' '.join([str(m) for m in matches[match].loser_matches]) if matches[match].loser_matches is not None else '', + get_match_table(matches[match]) + ) + row_no += 1 + col_no += 1 + return p_temp.MATCH_GRID % (width, height, width, height, grid_boxes) + +def get_leaderboard_table(leaderboard): + position = 1 + rows = '' + for team in [team if team is not None else '' for team in leaderboard]: + rows += p_temp.LEADERBOARD_ROW % (position, team) + position +=1 + html = p_temp.LEADERBOARD.decode('utf8') % (rows) + return html + +class Team: + name = '' + score = 0.0 + +class Match: + teams = None + running = 0 + link = '#' + winner = None + loser = None + winner_matches = None + loser_matches = None + +match_info = {} + +def get_match_info(match): + info = Match() + info.teams = [Team(), Team()] + info.winner_matches = [] + info.loser_matches = [] + for i in range(0, 2): + if 'winner' in match['teams'][i]: + info.winner_matches += match['teams'][i]['winner'] + if 'loser' in match['teams'][i]: + info.loser_matches += match['teams'][i]['loser'] + info.winner_matches = list(set(info.winner_matches)) + info.loser_matches = list(set(info.loser_matches)) + try: + row = db_fetch(match['database'], p_sql.MATCH_RESULTS, (match['table'], match['round'])) + info.teams[0].name = row[0] + info.teams[1].name = row[1] + info.teams[0].score = row[3] + row[5] + info.teams[1].score = row[4] + row[6] + if row[2] > 0: + info.teams[0].score += row[2] + else: + info.teams[1].score -= row[2] + except Exception as e: + for i in range(0, 2): + if isinstance(match['teams'][i], basestring): + info.teams[i].name = match['teams'][i] + else: + teams = [] + if 'winner' in match['teams'][i]: + teams += [ + match_info[winner_match].winner + for winner_match in match['teams'][i]['winner'] + ] + if 'loser' in match['teams'][i]: + teams += [ + match_info[loser_match].loser + for loser_match in match['teams'][i]['loser'] + ] + info.teams[i].name = '<br />'.join([ + team if team is not None else '??' + for team in teams] + ) if len([team for team in teams if team is not None]) > 0 else '' + + try: + row = db_fetch(match['database'], p_sql.BOARD_COUNT, (match['table'], match['round'])) + if row[1] > 0: + info.running = int(row[1]) + if row[1] == row[0]: + info.running = 0 + info.winner = info.teams[0].name if info.teams[0].score > info.teams[1].score else info.teams[1].name + info.loser = info.teams[1].name if info.teams[0].score > info.teams[1].score else info.teams[0].name + except Exception as e: + pass + return info + +grid = [] +for phase in settings['phases']: + grid.append([]) + for match in phase['matches']: + match_info[match['id']] = get_match_info(match) + match_info[match['id']].link = phase['link'] + grid[-1].append(match['id']) + +leaderboard_teams = {} +for phase in settings['phases']: + for match in phase['matches']: + if 'winner' in match: + winner_key = tuple(match['winner']) + if winner_key not in leaderboard_teams: + leaderboard_teams[winner_key] = [] + leaderboard_teams[winner_key].append(match_info[match['id']].winner) + if 'loser' in match: + loser_key = tuple(match['loser']) + if loser_key not in leaderboard_teams: + leaderboard_teams[loser_key] = [] + leaderboard_teams[loser_key].append(match_info[match['id']].loser) + +for positions, teams in leaderboard_teams.iteritems(): + positions = list(positions) + if len(positions) == len([team for team in teams if team is not None]): + for table_team in settings['teams']: + if table_team[0] in teams: + position = positions.pop(0) + leaderboard[position-1] = table_team[0] + +grid_columns = len(settings['phases']) +grid_rows = max([len(phase['matches']) for phase in settings['phases']]) +grid_height = grid_rows * (settings['page']['height'] + settings['page']['margin']) - settings['page']['margin'] +grid_width = grid_columns * (settings['page']['width'] + settings['page']['margin']) - settings['page']['margin'] + +output = open(settings['output'], 'w') +output.write(( + p_temp.PAGE % ( + p_temp.PAGE_HEAD % ( + p_temp.PAGE_HEAD_REFRESH % (settings['page']['refresh']) if settings['page']['refresh'] > 0 else '', + settings['page']['title'] + ), + p_temp.PAGE_BODY % ( + settings['page']['logoh'], + get_match_grid(grid, match_info, grid_width, grid_height), + get_leaderboard_table(leaderboard), + p_temp.PAGE_BODY_FOOTER.decode('utf8') % (datetime.now().strftime('%Y-%m-%d o %H:%M')) + ) + )).encode('utf8') +) + +shutil.copy(unicode(os.path.join(os.path.dirname(__file__), 'playoff.js')), + unicode(os.path.join(os.path.dirname(settings['output']), 'sklady/playoff.js'))) diff --git a/playoff/__init__.py b/playoff/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/playoff/__init__.py diff --git a/playoff/sql.py b/playoff/sql.py new file mode 100644 index 0000000..0bd2df7 --- /dev/null +++ b/playoff/sql.py @@ -0,0 +1,23 @@ +MATCH_RESULTS = ''' +SELECT t1.fullname, t2.fullname, matches.carry, matches.vph, matches.vpv, matches.corrh, matches.corrv +FROM #db#.matches matches +JOIN #db#.teams t1 + ON t1.id = #db#.matches.homet +JOIN #db#.teams t2 + ON t2.id = #db#.matches.visit +WHERE matches.tabl = %s AND matches.rnd = %s +''' + +BOARD_COUNT = ''' +SELECT segmentsperround*boardspersegment, SUM(sc1.contract IS NOT NULL AND sc2.contract IS NOT NULL) +FROM #db#.scores sc1 +JOIN #db#.scores sc2 + ON sc1.rnd = sc2.rnd + AND sc1.segment = sc2.segment + AND sc1.tabl = sc2.tabl + AND sc1.board = sc2.board + AND sc1.room = 1 + AND sc2.room = 2 +JOIN #db#.admin +WHERE sc1.tabl = %s AND sc1.rnd = %s +''' diff --git a/playoff/template.py b/playoff/template.py new file mode 100644 index 0000000..5fe855c --- /dev/null +++ b/playoff/template.py @@ -0,0 +1,116 @@ +#encoding=utf-8 + +MATCH_TABLE = ''' +<table border="0" cellspacing="0"> +<tr> +<td class="s12" width="%d"> </td> +<td class="bdcc2" width="%d"> wynik </td> +</tr> +%s +</table> +''' + +MATCH_TEAM_ROW = ''' +<tr> +<td class="bd1"> <a onmouseover="Tip('%s')" onmouseout="UnTip()">%s</a> </td> +<td class="bdc"> %.1f </td> +</tr> +''' + +MATCH_RUNNING = ''' +<a href="%s" target="_top"> +<img src="images/A.gif" /> +%d +<img src="images/A.gif" /> +</a> +''' + +MATCH_GRID = ''' +<div style="position: relative; width: %dpx; height: %dpx; margin: 10px"> +<canvas width="%d" height="%d" id="playoff_canvas"></canvas> +%s +<script src="sklady/playoff.js" type="text/javascript"></script> +</div> +''' + +MATCH_GRID_PHASE = ''' +<a href="%s" target="_top" style="display: inline-block; width: %dpx; text-align: center; position: absolute; top: 0; left: %dpx">%s</a> +''' + +MATCH_GRID_RUNNING_PHASE = ''' +<a href="%s" target="_top" style="display: inline-block; width: %dpx; text-align: center; position: absolute; top: 0; left: %dpx"> +<img src="images/A.gif" /> +%s +<img src="images/A.gif" /> +</a> +''' + +MATCH_BOX = ''' +<div style="position: absolute; left: %dpx; top: %dpx" data-id="%d" data-winner="%s" data-loser="%s" class="playoff_matchbox"> +%s +</div> +''' + +LEADERBOARD = ''' +<table border="0" cellspacing="0"> +<tr> +<td class="bdnl12" colspan="2" align="center"><b>KLASYFIKACJA KOŃCOWA</b></td> +</tr> +<tr> +<td class="e" colspan="2"> </td> +</tr> +<tr> +<td class="bdcc12"> miejsce </td> +<td class="bdcc2"> drużyna </td> +</tr> +%s +</table> +''' + +LEADERBOARD_ROW = ''' +<tr> +<td class="bdc1">%d</td> +<td class="bd"> %s </td> +</tr> +''' + +PAGE_HEAD = ''' +<meta http-equiv="Pragma" content="no-cache" /> +<meta http-equiv="Cache-Control" content="no-cache" /> +<meta name="robots" content="noarchive" /> +<meta http-equiv="expires" content="0" /> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="Generator" content="PlayOff" /> +%s +<title>%s</title> +<link rel="stylesheet" type="text/css" href="css/kolorki.css" /> +<script type="text/javascript" src="sklady/myAjax.js"></script> +''' + +PAGE_HEAD_REFRESH = ''' +<meta http-equiv="Refresh" content="%d" /> +''' + +PAGE_BODY = ''' +<script type="text/javascript" src="sklady/wz_tooltip.js"></script> +%s +%s +%s +%s +''' + +PAGE_BODY_FOOTER = ''' +<p class="f"> Admin ©Jan Romański'2005, PlayOff ©Michał Klichowicz'2017, strona wygenerowana %s</p> +''' + +PAGE = ''' +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +%s +</head> +<body class="all"> +%s +</body> +</html> +''' |