diff --git a/assets/js/pages/database/top_openings/TopOpeningsModal.js b/assets/js/pages/database/top_openings/TopOpeningsModal.js new file mode 100644 index 00000000..837d14aa --- /dev/null +++ b/assets/js/pages/database/top_openings/TopOpeningsModal.js @@ -0,0 +1,129 @@ +import Modal from 'bootstrap/js/dist/modal.js'; +import { Chart, registerables } from 'https://cdn.jsdelivr.net/npm/chart.js@4.4.2/+esm'; +import movesMetadataTable from '../../movesMetadataTable.js'; +import { progressModal } from '../../ProgressModal.js'; +import AbstractComponent from '../../../AbstractComponent.js'; +import { sanWebSocket } from '../../../SanWebSocket.js'; +import * as env from '../../../../env.js'; +import * as mode from '../../../../mode.js'; + +Chart.register(...registerables); + +export class TopOpeningsModal extends AbstractComponent { + _nBars = 25; + + mount() { + const handleBarClick = (event, clickedElements) => { + this.props.progressModal.props.modal.show(); + if (clickedElements.length === 0) { + return; + } + const { dataIndex, raw } = clickedElements[0].element.$context; + fetch(`${env.API_SCHEME}://${env.API_HOST}:${env.API_PORT}/${env.API_VERSION}/search`, { + method: 'POST', + headers: { + 'X-Api-Key': `${env.API_KEY}` + }, + body: JSON.stringify({ + Result: event.chart.data.datasets[0].label, + ECO: event.chart.data.labels[dataIndex] + }) + }) + .then(res => res.json()) + .then(res => { + this.props.movesMetadataTable.props = res[0]; + this.props.movesMetadataTable.mount(); + const add = { + movetext: res[0].movetext + }; + sanWebSocket.send(`/start classical ${mode.SAN} "${JSON.stringify(add).replace(/"/g, '\\"')}"`); + }) + .catch(error => { + // TODO + }) + .finally(() => { + this.props.modal.hide(); + this.props.progressModal.props.modal.hide(); + }); + } + + const options = { + animation: false, + categoryPercentage: 1.0, + barPercentage: 1.0, + onHover: function(event, el) { + event.native.target.style.cursor = el[0] ? 'pointer' : 'default'; + }, + onClick: handleBarClick, + scales: { + x: { + grid: { + display: false + } + }, + y: { + beginAtZero: true, + grid: { + display: false + } + } + } + } + + if (this.props.stats?.winRateForWhite) { + new Chart(document.getElementById('winRateForWhiteChart'), { + type: 'bar', + data: { + labels: this.props.stats.winRateForWhite.map(value => value.ECO).slice(0, this._nBars), + datasets: [{ + label: '1-0', + data: this.props.stats.winRateForWhite.map(value => value.total).slice(0, this._nBars), + backgroundColor: '#c0c0c0' + }] + }, + options: options + }); + } + + if (this.props.stats?.drawRate) { + new Chart(document.getElementById('drawRateChart'), { + type: 'bar', + data: { + labels: this.props.stats.drawRate.map(value => value.ECO).slice(0, this._nBars), + datasets: [{ + label: '1/2-1/2', + data: this.props.stats.drawRate.map(value => value.total).slice(0, this._nBars), + backgroundColor: '#888888' + }] + }, + options: options + }); + } + + if (this.props.stats?.winRateForBlack) { + new Chart(document.getElementById('winRateForBlackChart'), { + type: 'bar', + data: { + labels: this.props.stats.winRateForBlack.map(value => value.ECO).slice(0, this._nBars), + datasets: [{ + label: '0-1', + data: this.props.stats.winRateForBlack.map(value => value.total).slice(0, this._nBars), + backgroundColor: '#404040' + }] + }, + options: options + }); + } + } +} + +export const topOpeningsModal = new TopOpeningsModal( + document.getElementById('topOpeningsModal'), + { + modal: new Modal(document.getElementById('topOpeningsModal')), + form: document.querySelector('#topOpeningsModal form'), + movesMetadataTable: movesMetadataTable, + progressModal: progressModal, + stats: {} + } +); diff --git a/assets/js/pages/database/top_openings/index.js b/assets/js/pages/database/top_openings/index.js index 97d46dd8..8a1d02e2 100644 --- a/assets/js/pages/database/top_openings/index.js +++ b/assets/js/pages/database/top_openings/index.js @@ -1,4 +1,4 @@ -import topOpeningsModal from './topOpeningsModal.js'; +import { topOpeningsModal } from './TopOpeningsModal.js'; import boardActionsDropdown from '../../boardActionsDropdown.js'; import { gameStudyDropdown } from '../../GameStudyDropdown.js'; import historyButtons from '../../historyButtons.js'; @@ -20,8 +20,9 @@ await fetch(`${env.API_SCHEME}://${env.API_HOST}:${env.API_PORT}/${env.API_VERSI }) .then(res => res.json()) .then(res => { - topOpeningsModal.mount(res); - topOpeningsModal.modal.show(); + topOpeningsModal.props.stats = res; + topOpeningsModal.mount(); + topOpeningsModal.props.modal.show(); }) .catch(error => { // TODO diff --git a/assets/js/pages/database/top_openings/topOpeningsModal.js b/assets/js/pages/database/top_openings/topOpeningsModal.js deleted file mode 100644 index b1145357..00000000 --- a/assets/js/pages/database/top_openings/topOpeningsModal.js +++ /dev/null @@ -1,118 +0,0 @@ -import { Chart, registerables } from 'https://cdn.jsdelivr.net/npm/chart.js@4.4.2/+esm'; -import Modal from 'bootstrap/js/dist/modal.js'; -import movesMetadataTable from '../../movesMetadataTable.js'; -import { progressModal } from '../../ProgressModal.js'; -import { sanWebSocket } from '../../../SanWebSocket.js'; -import * as env from '../../../../env.js'; -import * as mode from '../../../../mode.js'; - -Chart.register(...registerables); - -const N_BARS = 25; - -const handleBarClick = (event, clickedElements) => { - progressModal.props.modal.show(); - if (clickedElements.length === 0) { - return; - } - const { dataIndex, raw } = clickedElements[0].element.$context; - fetch(`${env.API_SCHEME}://${env.API_HOST}:${env.API_PORT}/${env.API_VERSION}/search`, { - method: 'POST', - headers: { - 'X-Api-Key': `${env.API_KEY}` - }, - body: JSON.stringify({ - Result: event.chart.data.datasets[0].label, - ECO: event.chart.data.labels[dataIndex] - }) - }) - .then(res => res.json()) - .then(res => { - movesMetadataTable.props = res[0]; - movesMetadataTable.mount(); - const add = { - movetext: res[0].movetext - }; - sanWebSocket.send(`/start classical ${mode.SAN} "${JSON.stringify(add).replace(/"/g, '\\"')}"`); - }) - .catch(error => { - // TODO - }) - .finally(() => { - topOpeningsModal.modal.hide(); - progressModal.props.modal.hide(); - }); -} - -const options = { - animation: false, - categoryPercentage: 1.0, - barPercentage: 1.0, - onHover: function(event, el) { - event.native.target.style.cursor = el[0] ? 'pointer' : 'default'; - }, - onClick: handleBarClick, - scales: { - x: { - grid: { - display: false - } - }, - y: { - beginAtZero: true, - grid: { - display: false - } - } - } -} - -const topOpeningsModal = { - modal: new Modal(document.getElementById('topOpeningsModal')), - form: document.querySelector('#topOpeningsModal form'), - mount: (res) => { - const winRateForWhiteChart = document.getElementById('winRateForWhiteChart'); - new Chart(winRateForWhiteChart, { - type: 'bar', - data: { - labels: res.winRateForWhite.map(value => value.ECO).slice(0, N_BARS), - datasets: [{ - label: '1-0', - data: res.winRateForWhite.map(value => value.total).slice(0, N_BARS), - backgroundColor: '#c0c0c0' - }] - }, - options: options - }); - - const drawRateChart = document.getElementById('drawRateChart'); - new Chart(drawRateChart, { - type: 'bar', - data: { - labels: res.drawRate.map(value => value.ECO).slice(0, N_BARS), - datasets: [{ - label: '1/2-1/2', - data: res.drawRate.map(value => value.total).slice(0, N_BARS), - backgroundColor: '#888888' - }] - }, - options: options - }); - - const winRateForBlackChart = document.getElementById('winRateForBlackChart'); - new Chart(winRateForBlackChart, { - type: 'bar', - data: { - labels: res.winRateForBlack.map(value => value.ECO).slice(0, N_BARS), - datasets: [{ - label: '0-1', - data: res.winRateForBlack.map(value => value.total).slice(0, N_BARS), - backgroundColor: '#404040' - }] - }, - options: options - }); - } -} - -export default topOpeningsModal;