From eb0119aedb0a2c93b5020c10e0e8006ee0c4b0c1 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Fri, 23 Dec 2022 17:12:50 +0100 Subject: [PATCH] Make our own SVG sparkline, replacing jquery.sparkline.js. --- build.sh | 7 --- www/css/remoteglot.css | 20 +++++++- www/index.dev.html | 8 ++-- www/js/remoteglot.js | 101 ++++++++++++++++++++++++++++------------- 4 files changed, 92 insertions(+), 44 deletions(-) diff --git a/build.sh b/build.sh index 848714a..c970b13 100755 --- a/build.sh +++ b/build.sh @@ -3,22 +3,15 @@ # Download http://dl.google.com/closure-compiler/compiler-latest.zip # and unzip it in closure/ before running this script. -# The JQuery build comes from http://projects.jga.me/jquery-builder/, -# more specifically -# -# https://raw.githubusercontent.com/jgallen23/jquery-builder/0.7.0/dist/2.1.1/jquery-deprecated-sizzle.js - umask 022 java -jar closure-compiler-v20221004.jar \ --language_in ECMASCRIPT_2018 \ --compilation_level SIMPLE \ --js_output_file=www/js/remoteglot.min.js \ - www/js/jquery-deprecated-sizzle.js \ www/js/chessboard-0.3.0.js \ www/js/chess.js \ www/js/json_delta.js \ - www/js/jquery.sparkline.js \ www/js/remoteglot.js cat www/css/chessboard-0.3.0.css www/css/remoteglot.css | sass --scss -t compressed > www/css/remoteglot.min.css diff --git a/www/css/remoteglot.css b/www/css/remoteglot.css index a928985..c2aba8f 100644 --- a/www/css/remoteglot.css +++ b/www/css/remoteglot.css @@ -14,17 +14,35 @@ h3 { #scorecontainer { font-size: x-large; margin-top: 0; + display: grid; + grid-template-columns: max-content 1fr; + gap: 12px; } #score { - float: left; + grid-column: 1; } #scoresparkcontainer { + grid-column: 2; overflow: hidden; + height: 0.85em; + margin-top: 0.15em; + width: 100%; } #scorespark { margin-left: 0.5em; margin-right: 0.5em; } +#sparklinehover { + position: absolute; + display: none; + background-color: rgba(0, 0, 0, 0.6); + color: white; + font-size: 10px; + white-space: nowrap; + padding: 5px; + border: 1px solid white; + z-index: 10000; +} #pvcontainer { clear: left; margin-top: 1em; diff --git a/www/index.dev.html b/www/index.dev.html index 139075e..e04ef3a 100644 --- a/www/index.dev.html +++ b/www/index.dev.html @@ -12,11 +12,9 @@ - - @@ -39,9 +37,9 @@
Score: -
- -
+ + +

PV:

diff --git a/www/js/remoteglot.js b/www/js/remoteglot.js index 61c390f..beaf63f 100644 --- a/www/js/remoteglot.js +++ b/www/js/remoteglot.js @@ -1361,6 +1361,8 @@ var update_board = function() { } var update_sparkline = function(data) { + let scorespark = document.getElementById('scoresparkcontainer'); + scorespark.textContent = ''; if (data && data['score_history']) { var first_move_num = undefined; for (var halfmove_num in data['score_history']) { @@ -1376,17 +1378,13 @@ var update_sparkline = function(data) { } // Possibly truncate some moves if we don't have enough width. - // FIXME: Sometimes width() for #scorecontainer (and by extent, - // #scoresparkcontainer) on Chrome for mobile seems to start off - // at something very small, and then suddenly snap back into place. - // Figure out why. - var max_moves = Math.floor(document.getElementById("scoresparkcontainer").getBoundingClientRect().width / 5) - 5; + var max_moves = Math.floor(scorespark.getBoundingClientRect().width / 5) - 3; if (last_move_num - first_move_num > max_moves) { first_move_num = last_move_num - max_moves; } - var min_score = -100; - var max_score = 100; + var min_score = -1; + var max_score = 1; var last_score = null; var scores = []; for (var halfmove_num = first_move_num; halfmove_num <= last_move_num; ++halfmove_num) { @@ -1401,36 +1399,77 @@ var update_sparkline = function(data) { if (data['score']) { scores.push(compute_plot_score(data['score'])); } - // FIXME: at some widths, calling sparkline() seems to push - // #scorecontainer under the board. - $('#scorespark').unbind('sparklineClick'); - $('#scorespark').sparkline(scores, { - type: 'bar', - zeroColor: 'gray', - chartRangeMin: min_score, - chartRangeMax: max_score, - tooltipFormatter: function(sparkline, options, fields) { - // score_history contains the Nth _position_, but format_tooltip - // wants to format the Nth _move_; thus the -1. - return format_tooltip(data, fields[0].offset + first_move_num - 1); + + const h = scorespark.getBoundingClientRect().height; + + let base_y = h - h * min_score / (min_score - max_score); + for (let i = 0; i < scores.length; ++i) { + let rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); + //rect.setAttributeNS(null, 'stroke', "#000000"); + rect.setAttributeNS(null, 'x', i * 5) + rect.setAttributeNS(null, 'width', 4); + let extent = scores[i] * h / (max_score - min_score); + if (extent > 0 && extent < 1) { + extent = 1; + } else if (extent < 0 && extent > -1) { + extent = -1; } - }); - $('#scorespark').unbind('sparklineClick'); - $('#scorespark').bind('sparklineClick', function(event) { - var sparkline = event.sparklines[0]; - var region = sparkline.getCurrentRegionFields(); - if (region[0].offset !== undefined) { - show_line(0, first_move_num + region[0].offset - 1); + + let color; + if (scores[i] === 0) { + color = [0.5, 0.5, 0.5]; + rect.setAttributeNS(null, 'y', base_y - 1); + rect.setAttributeNS(null, 'height', 1); + } else if (scores[i] > 0) { + color = [0.2, 0.4, 0.8]; + rect.setAttributeNS(null, 'y', base_y - extent); + rect.setAttributeNS(null, 'height', extent); + } else { + color = [1.0, 0.267, 0.267]; + rect.setAttributeNS(null, 'y', base_y); + rect.setAttributeNS(null, 'height', -extent); } - }); - } else { - document.getElementById("scorespark").textContent = ""; + let hlcolor = [color[0], color[1], color[2]]; + if (scores[i] !== 0) { + hlcolor[0] = Math.min(hlcolor[0] * 1.4, 1.0); + hlcolor[1] = Math.min(hlcolor[1] * 1.4, 1.0); + hlcolor[2] = Math.min(hlcolor[2] * 1.4, 1.0); + } + rect.style.fill = 'rgb(' + color[0]*100.0 + '%, ' + color[1]*100.0 + '%, ' + color[2]*100.0 + '%)'; + + // score_history contains the Nth _position_, but format_tooltip + // wants to format the Nth _move_; thus the -1. + const tooltip = format_tooltip(data, i + first_move_num - 1); + rect.addEventListener('mouseenter', (e) => draw_hover(e, hlcolor, tooltip)); + rect.addEventListener('mousemove', (e) => draw_hover(e, hlcolor, tooltip)); + rect.addEventListener('mouseleave', (e) => hide_hover(e, color)); + rect.addEventListener('click', (e) => show_line(0, i + first_move_num - 1)); + scorespark.appendChild(rect); + } } - } else { - document.getElementById("scorespark").textContent = ""; } } +var draw_hover = function(e, color, tooltip) { + e.target.style.fill = 'rgb(' + color[0]*100.0 + '%, ' + color[1]*100.0 + '%, ' + color[2]*100.0 + '%)'; + + let hover = document.getElementById('sparklinehover'); + hover.textContent = tooltip; + hover.style.display = 'initial'; + + let left = Math.max(e.pageX + 10, window.pageXOffset); + let top = Math.max(e.pageY - hover.getBoundingClientRect().height, window.pageYOffset); + left = Math.min(left, window.pageXOffset + document.documentElement.clientWidth - hover.getBoundingClientRect().width); + + hover.style.left = left + 'px'; + hover.style.top = top + 'px'; + +} +var hide_hover = function(e, color) { + e.target.style.fill = 'rgb(' + color[0]*100.0 + '%, ' + color[1]*100.0 + '%, ' + color[2]*100.0 + '%)'; + document.getElementById('sparklinehover').style.display = 'none'; +} + /** * @param {number} num_viewers */ -- 2.39.2