X-Git-Url: https://git.sesse.net/?p=remoteglot;a=blobdiff_plain;f=www%2Fjs%2Fremoteglot.js;h=98d9ac4ece8c3e7667459275837635c2f925b9fd;hp=3fb0f179244b52fac38303550841ab8c2e580cab;hb=731dad8cbe2455aefe534bddce20fca85abd3d2e;hpb=860c85720480b9dfb1bb4c300ca3e9b04650a336 diff --git a/www/js/remoteglot.js b/www/js/remoteglot.js index 3fb0f17..98d9ac4 100644 --- a/www/js/remoteglot.js +++ b/www/js/remoteglot.js @@ -1,34 +1,45 @@ -var board = []; +var board = null; +var hiddenboard = null; var arrows = []; -var arrow_targets = []; var occupied_by_arrows = []; +var refutation_lines = []; +var move_num = 1; +var toplay = 'W'; var ims = 0; +var sort_refutation_lines_by_score = 0; var highlight_from = undefined; var highlight_to = undefined; +var unique = Math.random(); -var request_update = function(board, first) { +var fen = null; +var display_lines = []; +var current_display_line = null; +var current_display_move = null; + +var request_update = function(board) { $.ajax({ - //url: "http://analysis.sesse.net/analysis.pl?first=" + first - url: "http://analysis.sesse.net:5000/analysis.pl?ims=" + ims + url: "http://analysis.sesse.net/analysis.pl?ims=" + ims + "&unique=" + unique + //url: "http://analysis.sesse.net:5000/analysis.pl?ims=" + ims + "&unique=" + unique }).done(function(data, textstatus, xhr) { ims = xhr.getResponseHeader('X-Remoteglot-Last-Modified'); - update_board(board, data); + var num_viewers = xhr.getResponseHeader('X-Remoteglot-Num-Viewers'); + update_board(board, data, num_viewers); + }).fail(function() { + // Wait ten seconds, then try again. + setTimeout(function() { request_update(board); }, 10000); }); } var clear_arrows = function() { for (var i = 0; i < arrows.length; ++i) { - jsPlumb.detach(arrows[i].connection1); - jsPlumb.detach(arrows[i].connection2); + if (arrows[i].svg) { + arrows[i].svg.parentElement.removeChild(arrows[i].svg); + delete arrows[i].svg; + } } arrows = []; - for (var i = 0; i < arrow_targets.length; ++i) { - document.body.removeChild(arrow_targets[i]); - } - arrow_targets = []; - - occupied_by_arrows = []; + occupied_by_arrows = []; for (var y = 0; y < 8; ++y) { occupied_by_arrows.push([false, false, false, false, false, false, false, false]); } @@ -82,86 +93,103 @@ var interfering_arrow = function(from, to) { return false; } -var add_target = function() { - var elem = document.createElement("div"); - $(elem).addClass("window"); - elem.id = "target" + arrow_targets.length; - document.body.appendChild(elem); - arrow_targets.push(elem); - return elem.id; +var point_from_start = function(x1, y1, x2, y2, t, u) { + var dx = x2 - x1; + var dy = y2 - y1; + + var norm = 1.0 / Math.sqrt(dx * dx + dy * dy); + dx *= norm; + dy *= norm; + + var x = x1 + dx * t + dy * u; + var y = y1 + dy * t - dx * u; + return x + " " + y; } - + +var point_from_end = function(x1, y1, x2, y2, t, u) { + var dx = x2 - x1; + var dy = y2 - y1; + + var norm = 1.0 / Math.sqrt(dx * dx + dy * dy); + dx *= norm; + dy *= norm; + + var x = x2 + dx * t + dy * u; + var y = y2 + dy * t - dx * u; + return x + " " + y; +} + var position_arrow = function(arrow) { + if (arrow.svg) { + arrow.svg.parentElement.removeChild(arrow.svg); + delete arrow.svg; + } + if (current_display_line !== null) { + return; + } + + var pos = $(".square-a8").position(); + var zoom_factor = $("#board").width() / 400.0; var line_width = arrow.line_width * zoom_factor; var arrow_size = arrow.arrow_size * zoom_factor; - var square_width = Math.floor(($("#board").width() - 1) / 8); - var from_y = (7 - arrow.from_row + 0.5)*square_width + 1; - var to_y = (7 - arrow.to_row + 0.5)*square_width + 1; - var from_x = (arrow.from_col + 0.5)*square_width + 1; - var to_x = (arrow.to_col + 0.5)*square_width + 1; - - var dx = to_x - from_x; - var dy = to_y - from_y; - var len = Math.sqrt(dx * dx + dy * dy); - dx /= len; - dy /= len; - var pos = $("#board").position(); - $("#" + arrow.s1).css({ top: pos.top + from_y + (0.5 * arrow_size) * dy, left: pos.left + from_x + (0.5 * arrow_size) * dx }); - $("#" + arrow.d1).css({ top: pos.top + to_y - (0.5 * arrow_size) * dy, left: pos.left + to_x - (0.5 * arrow_size) * dx }); - $("#" + arrow.s1v).css({ top: pos.top + from_y - 0 * dy, left: pos.left + from_x - 0 * dx }); - $("#" + arrow.d1v).css({ top: pos.top + to_y + 0 * dy, left: pos.left + to_x + 0 * dx }); - - if (arrow.connection1) { - jsPlumb.detach(arrow.connection1); - } - if (arrow.connection2) { - jsPlumb.detach(arrow.connection2); - } - arrow.connection1 = jsPlumb.connect({ - source: arrow.s1, - target: arrow.d1, - connector:["Straight"], - cssClass:"c1", - endpoint:"Blank", - endpointClass:"c1Endpoint", - anchor:"Continuous", - paintStyle:{ - lineWidth:line_width, - strokeStyle:arrow.fg_color, - outlineWidth:1, - outlineColor:"#666", - opacity:"60%" - } - }); - arrow.connection2 = jsPlumb.connect({ - source: arrow.s1v, - target: arrow.d1v, - connector:["Straight"], - cssClass:"vir", - endpoint:"Blank", - endpointClass:"c1Endpoint", - anchor:"Continuous", - paintStyle:{ - lineWidth:0, - strokeStyle:arrow.fg_color, - outlineWidth:0, - outlineColor:"#666", - }, - overlays : [ - ["Arrow", { - cssClass:"l1arrow", - location:1.0, - width: arrow_size, - length: arrow_size, - paintStyle: { - lineWidth:line_width, - strokeStyle:"#000", - }, - }] - ] - }); + var square_width = $(".square-a8").width(); + var from_y = (7 - arrow.from_row + 0.5)*square_width; + var to_y = (7 - arrow.to_row + 0.5)*square_width; + var from_x = (arrow.from_col + 0.5)*square_width; + var to_x = (arrow.to_col + 0.5)*square_width; + + var SVG_NS = "http://www.w3.org/2000/svg"; + var XHTML_NS = "http://www.w3.org/1999/xhtml"; + var svg = document.createElementNS(SVG_NS, "svg"); + svg.setAttribute("width", $("#board").width()); + svg.setAttribute("height", $("#board").height()); + svg.setAttribute("style", "position: absolute"); + svg.setAttribute("position", "absolute"); + svg.setAttribute("version", "1.1"); + svg.setAttribute("class", "c1"); + svg.setAttribute("xmlns", XHTML_NS); + + var x1 = from_x; + var y1 = from_y; + var x2 = to_x; + var y2 = to_y; + + // Draw the line. + var outline = document.createElementNS(SVG_NS, "path"); + outline.setAttribute("d", "M " + point_from_start(x1, y1, x2, y2, arrow_size / 2, 0) + " L " + point_from_end(x1, y1, x2, y2, -arrow_size / 2, 0)); + outline.setAttribute("xmlns", XHTML_NS); + outline.setAttribute("stroke", "#666"); + outline.setAttribute("stroke-width", line_width + 2); + outline.setAttribute("fill", "none"); + svg.appendChild(outline); + + var path = document.createElementNS(SVG_NS, "path"); + path.setAttribute("d", "M " + point_from_start(x1, y1, x2, y2, arrow_size / 2, 0) + " L " + point_from_end(x1, y1, x2, y2, -arrow_size / 2, 0)); + path.setAttribute("xmlns", XHTML_NS); + path.setAttribute("stroke", arrow.fg_color); + path.setAttribute("stroke-width", line_width); + path.setAttribute("fill", "none"); + svg.appendChild(path); + + // Then the arrow head. + var head = document.createElementNS(SVG_NS, "path"); + head.setAttribute("d", + "M " + point_from_end(x1, y1, x2, y2, 0, 0) + + " L " + point_from_end(x1, y1, x2, y2, -arrow_size, -arrow_size / 2) + + " L " + point_from_end(x1, y1, x2, y2, -arrow_size * .623, 0.0) + + " L " + point_from_end(x1, y1, x2, y2, -arrow_size, arrow_size / 2) + + " L " + point_from_end(x1, y1, x2, y2, 0, 0)); + head.setAttribute("xmlns", XHTML_NS); + head.setAttribute("stroke", "#000"); + head.setAttribute("stroke-width", "1"); + head.setAttribute("fill", "#f66"); + svg.appendChild(head); + + $(svg).css({ top: pos.top, left: pos.left }); + document.body.appendChild(svg); + arrow.svg = svg; } var create_arrow = function(from_square, to_square, fg_color, line_width, arrow_size) { @@ -172,16 +200,12 @@ var create_arrow = function(from_square, to_square, fg_color, line_width, arrow_ // Create arrow. var arrow = { - s1: add_target(), - d1: add_target(), - s1v: add_target(), - d1v: add_target(), from_col: from_col, from_row: from_row, to_col: to_col, to_row: to_row, line_width: line_width, - arrow_size: arrow_size, + arrow_size: arrow_size, fg_color: fg_color }; @@ -189,6 +213,20 @@ var create_arrow = function(from_square, to_square, fg_color, line_width, arrow_ arrows.push(arrow); } +var compare_by_sort_key = function(refutation_lines, a, b) { + var ska = refutation_lines[a].sort_key; + var skb = refutation_lines[b].sort_key; + if (ska < skb) return -1; + if (ska > skb) return 1; + return 0; +}; + +var compare_by_score = function(refutation_lines, a, b) { + var sa = parseInt(refutation_lines[b].score_sort_key); + var sb = parseInt(refutation_lines[a].score_sort_key); + return sa - sb; +} + // Fake multi-PV using the refutation lines. Find all “relevant” moves, // sorted by quality, descending. var find_nonstupid_moves = function(data, margin) { @@ -223,7 +261,7 @@ var find_nonstupid_moves = function(data, margin) { moves.push(move); } } - moves = moves.sort(function(a, b) { return parseInt(data.refutation_lines[b].score_sort_key) - parseInt(data.refutation_lines[a].score_sort_key); }); + moves = moves.sort(function(a, b) { return compare_by_score(data.refutation_lines, a, b) }); moves.unshift(data.pv_uci[0]); return moves; @@ -233,16 +271,25 @@ var thousands = function(x) { return String(x).split('').reverse().join('').replace(/(\d{3}\B)/g, '$1,').split('').reverse().join(''); } -var print_pv = function(pretty_pv, move_num, toplay, limit) { +var print_pv = function(fen, uci_pv, pretty_pv, move_num, toplay, limit) { + display_lines.push({ + start_fen: fen, + uci_pv: uci_pv, + pretty_pv: pretty_pv + }); + var pv = ''; var i = 0; if (toplay == 'B') { - pv = move_num + '. … ' + pretty_pv[0]; + var move = "" + pretty_pv[0] + ""; + pv = move_num + '. … ' + move; toplay = 'W'; ++i; + ++move_num; } - ++move_num; for ( ; i < pretty_pv.length; ++i) { + var move = "" + pretty_pv[i] + ""; + if (toplay == 'W') { if (i > limit) { return pv + ' (…)'; @@ -250,46 +297,107 @@ var print_pv = function(pretty_pv, move_num, toplay, limit) { if (pv != '') { pv += ' '; } - pv += move_num + '. ' + pretty_pv[i]; + pv += move_num + '. ' + move; ++move_num; toplay = 'B'; } else { - pv += ' ' + pretty_pv[i]; + pv += ' ' + move; toplay = 'W'; } } return pv; } -var compare_by_sort_key = function(data, a, b) { - var ska = data.refutation_lines[a].sort_key; - var skb = data.refutation_lines[b].sort_key; - if (ska < skb) return -1; - if (ska > skb) return 1; - return 0; -}; - var update_highlight = function() { $("#board").find('.square-55d63').removeClass('nonuglyhighlight'); - if (highlight_from !== undefined && highlight_to !== undefined) { + if (current_display_line === null && highlight_from !== undefined && highlight_to !== undefined) { $("#board").find('.square-' + highlight_from).addClass('nonuglyhighlight'); $("#board").find('.square-' + highlight_to).addClass('nonuglyhighlight'); } } -var update_board = function(board, data) { +var update_refutation_lines = function(board) { + if (display_lines.length > 1) { + display_lines = [ display_lines[0] ]; + } + + var tbl = $("#refutationlines"); + tbl.empty(); + + var moves = []; + for (var move in refutation_lines) { + moves.push(move); + } + var compare = sort_refutation_lines_by_score ? compare_by_score : compare_by_sort_key; + moves = moves.sort(function(a, b) { return compare(refutation_lines, a, b) }); + for (var i = 0; i < moves.length; ++i) { + var line = refutation_lines[moves[i]]; + + var tr = document.createElement("tr"); + + var move_td = document.createElement("td"); + tr.appendChild(move_td); + $(move_td).addClass("move"); + if (line.pv_uci.length == 0) { + $(move_td).text(line.pretty_move); + } else { + var move = "" + line.pretty_move + ""; + $(move_td).html(move); + } + + var score_td = document.createElement("td"); + tr.appendChild(score_td); + $(score_td).addClass("score"); + $(score_td).text(line.pretty_score); + + var depth_td = document.createElement("td"); + tr.appendChild(depth_td); + $(depth_td).addClass("depth"); + $(depth_td).text("d" + line.depth); + + var pv_td = document.createElement("td"); + tr.appendChild(pv_td); + $(pv_td).addClass("pv"); + $(pv_td).html(print_pv(fen, line.pv_uci, line.pv_pretty, move_num, toplay, 10)); + + tbl.append(tr); + } + + // Make one of the links clickable and the other nonclickable. + if (sort_refutation_lines_by_score) { + $("#sortbyscore0").html("Move"); + $("#sortbyscore1").html("Score"); + } else { + $("#sortbyscore0").html("Move"); + $("#sortbyscore1").html("Score"); + } +} + +var update_board = function(board, data, num_viewers) { + display_lines = []; + // The headline. var headline = 'Analysis'; if (data.position.last_move !== 'none') { - headline += ' after ' + data.position.move_num + '. '; + headline += ' after ' if (data.position.toplay == 'W') { - headline += '… '; + headline += (data.position.move_num-1) + '… '; + } else { + headline += data.position.move_num + '. '; } headline += data.position.last_move; } $("#headline").text(headline); + if (num_viewers === null) { + $("#numviewers").text(""); + } else if (num_viewers == 1) { + $("#numviewers").text("You are the only current viewer"); + } else { + $("#numviewers").text(num_viewers + " current viewers"); + } + // The score. if (data.score !== null) { $("#score").text(data.score); @@ -314,7 +422,8 @@ var update_board = function(board, data) { } // Update the board itself. - board.position(data.position.fen); + fen = data.position.fen; + update_displayed_line(); if (data.position.last_move_uci) { highlight_from = data.position.last_move_uci.substr(0, 2); @@ -325,8 +434,7 @@ var update_board = function(board, data) { update_highlight(); // Print the PV. - var pv = print_pv(data.pv_pretty, data.position.move_num, data.position.toplay); - $("#pv").text(pv); + $("#pv").html(print_pv(data.position.fen, data.pv_uci, data.pv_pretty, data.position.move_num, data.position.toplay)); // Update the PV arrow. clear_arrows(); @@ -380,52 +488,82 @@ var update_board = function(board, data) { } } - // Show the refutation lines. - var tbl = $("#refutationlines"); - tbl.empty(); + // Update the refutation lines. + fen = data.position.fen; + move_num = data.position.move_num; + toplay = data.position.toplay; + refutation_lines = data.refutation_lines; + update_refutation_lines(board); - moves = []; - for (var move in data.refutation_lines) { - moves.push(move); - } - moves = moves.sort(function(a, b) { return compare_by_sort_key(data, a, b) }); - for (var i = 0; i < moves.length; ++i) { - var line = data.refutation_lines[moves[i]]; + // Next update. + setTimeout(function() { request_update(board); }, 100); +} - var tr = document.createElement("tr"); +var resort_refutation_lines = function(sort_by_score) { + sort_refutation_lines_by_score = sort_by_score; + update_refutation_lines(board); +} - var move_td = document.createElement("td"); - tr.appendChild(move_td); - $(move_td).addClass("move"); - $(move_td).text(line.pretty_move); +var show_line = function(line_num, move_num) { + if (line_num == -1) { + current_display_line = null; + current_display_move = null; + } else { + current_display_line = display_lines[line_num]; + current_display_move = move_num; + } + update_displayed_line(); + update_highlight(); + redraw_arrows(); +} - var score_td = document.createElement("td"); - tr.appendChild(score_td); - $(score_td).addClass("score"); - $(score_td).text(line.pretty_score); +var prev_move = function() { + --current_display_move; + update_displayed_line(); +} - var depth_td = document.createElement("td"); - tr.appendChild(depth_td); - $(depth_td).addClass("depth"); - $(depth_td).text("d" + line.depth); +var next_move = function() { + ++current_display_move; + update_displayed_line(); +} - var pv_td = document.createElement("td"); - tr.appendChild(pv_td); - $(pv_td).addClass("pv"); - $(pv_td).text(print_pv(line.pv_pretty, data.position.move_num, data.position.toplay, 10)); +var update_displayed_line = function() { + if (current_display_line === null) { + $("#linenav").hide(); + $("#linemsg").show(); + board.position(fen); + return; + } - tbl.append(tr); + $("#linenav").show(); + $("#linemsg").hide(); + + if (current_display_move == 0) { + $("#prevmove").html("Previous"); + } else { + $("#prevmove").html("Previous"); + } + if (current_display_move == current_display_line.uci_pv.length - 1) { + $("#nextmove").html("Next"); + } else { + $("#nextmove").html("Next"); } - // Next update. - setTimeout(function() { request_update(board, 0); }, 100); + hiddenboard.position(current_display_line.start_fen, false); + for (var i = 0; i <= current_display_move; ++i) { + var move = current_display_line.uci_pv[i]; + move = move.substr(0, 2) + "-" + move.substr(2, 4); + hiddenboard.move(move, false); + } + board.position(hiddenboard.position()); } var init = function() { // Create board. board = new ChessBoard('board', 'start'); + hiddenboard = new ChessBoard('hiddenboard', 'start'); - request_update(board, 1); + request_update(board); $(window).resize(function() { board.resize(); update_highlight();