diff --git a/layouts/index.html b/layouts/index.html index 27ca3be05cea509cfb3b6fe2288aabe6109e3fc4..be64c5e803621a1a65050d0010e6a4a34af5ccec 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -66,33 +66,60 @@ </article> {{ if eq .RelPermalink "/" }} - <div class="charts-container" style="display: flex; flex-direction: column; align-items: center;"> + <div class="charts-container" style="display: flex; flex-direction: column; align-items: center; gap: 2rem;"> <h1 style="text-align: center; margin-bottom: 50px;">Statistics</h1> - <!-- Charts --> - <!-- Select filter control --> - <label for="statistics_filter">Choose filter:</label> - <select name="statistics_filter" id="statistics_filter" style="margin-bottom: 1rem;"> - <!-- <option value="overview">Overview</option> --> - <option value="category">Category</option> - <option value="license">License</option> - <option value="governance">Governance</option> - <option value="standard">Standard</option> - <option value="mainorganisation">Main Organization</option> - <option value="functionalities">Functionalities</option> - <option value="standardscategorycompliance">Standards Category Compliance</option> - <option value="dataencodingstandards">Data Encoding Standards</option> - <option value="dataaccessstandards">Data Access Standards</option> - <option value="processingstandards">Processing Standards</option> - <option value="visualisationstandards">Visualisation Standards</option> - </select> - <div id="chart_container" - style="width: 100%; height: 500px; display: flex; flex-direction: row; justify-content: center;" - > - <canvas id="chart" style="margin: 1rem;"></canvas> - </div> <div style="margin-top: 2rem;"> <h3>Total number of projects: <span id="total_number_of_projects">0</span></h3> </div> + <!-- Charts --> + <div style="width: 100%; display: flex; flex-direction: row; flex-flow: row wrap; justify-content: center; align-items: center; gap: 2rem;"> + <!-- Category chart --> + <div style="width: 300px; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 0.2rem;"> + <canvas id="chart_category" style="height: 300px;"></canvas> + <h4 style="height: 2rem; width: 100%; text-align: center;">Categories</h4> + </div> + <!-- Governance chart --> + <div style="width: 300px; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 0.2rem;"> + <canvas id="chart_governance" style="height: 300px;"></canvas> + <h4 style="height: 2rem; width: 100%; text-align: center;">Governance</h4> + </div> + <!-- Main programming language chart --> + <div style="width: 300px; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 0.2rem;"> + <canvas id="chart_main_programming_language" style="height: 300px;"></canvas> + <h4 style="height: 2rem; width: 100%; text-align: center;">Main programming language</h4> + </div> + </div> + <div style="width: 100%; display: flex; flex-direction: row; justify-content: center;"> + <!-- Top 5 most popular licenses --> + <div> + <div style="display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 0.2rem;"> + <canvas id="chart_license_top" style="height: 370px;"></canvas> + <h4>First 5 most popular FOSS licenses in the geospatial system</h4> + </div> + </div> + </div> + <div> + <!-- Select filter control --> + <h3 style="width: 100%; text-align: center;">Other statistics:</h3> + <select name="statistics_filter" id="statistics_filter" style="margin-bottom: 1rem;"> + <!-- <option value="overview">Overview</option> --> + <!-- <option value="category">Category</option> --> + <option value="license">License</option> + <!-- <option value="governance">Governance</option> --> + <option value="standard">Standard</option> + <option value="mainorganisation">Main Organization</option> + <option value="functionalities">Functionalities</option> + <option value="standardscategorycompliance">Standards Category Compliance</option> + <option value="dataencodingstandards">Data Encoding Standards</option> + <option value="dataaccessstandards">Data Access Standards</option> + <option value="processingstandards">Processing Standards</option> + <option value="visualisationstandards">Visualisation Standards</option> + </select> + <div id="chart_container" style="width: 100%; height: 500px; display: flex; flex-direction: row; justify-content: center;"> + <canvas id="chart" style="margin: 1rem; height: 370px;"></canvas> + </div> + </div> + </div> <div style="margin-top: 50px;"> diff --git a/static/js/custom.js b/static/js/custom.js index 873bf9690156f2d08b890b70763fc1bae4357fcc..f321ea9eb69812c4f9b93f7507e14c633cab7b7c 100644 --- a/static/js/custom.js +++ b/static/js/custom.js @@ -1,4 +1,7 @@ let chart = null; +let chartCategory = null; +let chartGovernance = null; +let chartLicense = null; window.addEventListener("load", async (event) => { var coll = document.getElementsByClassName("collapsible-activator"); @@ -15,7 +18,8 @@ window.addEventListener("load", async (event) => { }); } - await drawGraph("category"); + await updateTotalNumberOfProjects(); + await drawGraph("dataencodingstandards"); await initializeDashboardGraphs(); let contributeModal = document.getElementById("contribute-modal"); @@ -124,10 +128,76 @@ function getRandomColorsRGB(n) { return colors; } -async function drawGraph(filter) { - await updateTotalNumberOfProjects(); +async function getReposData(filter) { + let result = { data: null, labels: null }; + let reposResponse = { success: false, repos: [] }; - hideElement("chart_container"); + switch (filter) { + case "overview": + break; + case "category": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/category"); + break; + case "license": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/license"); + break; + case "governance": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/governance"); + break; + case "standard": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/standard"); + break; + case "mainorganisation": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/mainorganisation"); + break; + case "functionalities": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/functionalities"); + break; + case "standardscategorycompliance": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/standardscategorycompliance"); + break; + case "dataencodingstandards": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/dataencodingstandards"); + break; + case "dataaccessstandards": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/dataaccessstandards"); + break; + case "processingstandards": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/processingstandards"); + break; + case "visualisationstandards": + reposResponse = await fetch("https://www.oss4geo.org/api/statistics/visualisationstandards"); + break; + case "programminglanguages": + reposResponse = await fetch("http://localhost:4444/api/statistics/programminglanguages"); + break; + default: + console.log("ERROR: Unknown filter!"); + return null; + } + + reposResponse = await reposResponse.json(); + if(reposResponse.success) { + reposResponse.repos.forEach(repo => { + if(repo.value == null || repo.value == "") { + repo.value = "Unknown"; + } + }); + + // Sort repos array by length + // let repos = reposResponse.repos.sort((a, b) => a.value.length - b.value.length); + // Sort repos by count ASC + let repos = reposResponse.repos.sort((a, b) => b.count - a.count); + // console.log(repos); + result.labels = repos.map(repo => repo.value); + result.data = repos.map(repo => repo.count); + } + + return result; +} + +async function drawGraph(filter) { + // hideElement("chart_container"); let reposResponse = { success: false, repos: [] }; let dataSetLabel = null; let labels = null; @@ -233,11 +303,89 @@ async function drawGraph(filter) { showElement("chart_container"); } +async function drawPieChart(chart, canvasId, filter, data, labels, dataSetLabel) { + if(chart) { + chart.destroy(); + chart = null; + } + + chart = new Chart( + document.getElementById(canvasId), + { + type: 'pie', + data: { + labels: labels, + datasets: [{ + label: dataSetLabel, + data: data, + backgroundColor: getRandomColorsRGB(data.length), + }] + }, + options: { + plugins: { + legend: { + display: false + } + } + } + } + ); + + return chart; +} + +async function drawBarChart(chart, canvasId, filter, data, labels, dataSetLabel) { + if(chart) { + chart.destroy(); + chart = null; + } + + chart = new Chart( + document.getElementById(canvasId), + { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: dataSetLabel, + data: data, + backgroundColor: getRandomColorsRGB(data.length), + }] + }, + options: { + plugins: { + legend: { + display: false + } + } + } + } + ); + + return chart; +} + async function initializeDashboardGraphs() { + const reposByCategory = await getReposData("category"); + await drawPieChart(chartCategory, "chart_category", "category", reposByCategory.data, reposByCategory.labels, "Category"); + + const reposByGovernance = await getReposData("governance"); + await drawPieChart(chartGovernance, "chart_governance", "governance", reposByGovernance.data, reposByGovernance.labels, "Governance"); + + const reposByProgrammingLanguage = await getReposData("programminglanguages"); + await drawPieChart(chartGovernance, "chart_main_programming_language", "programminglanguages", reposByProgrammingLanguage.data, reposByProgrammingLanguage.labels, "Language"); + + const reposByLicense = await getReposData("license"); + + const reposByLicenseTop5 = { + data: reposByLicense.data.slice(0,5 ), + labels: reposByLicense.labels.slice(0, 5) + }; + await drawBarChart(chartGovernance, "chart_license_top", "license", reposByLicenseTop5.data, reposByLicenseTop5.labels, "License"); + const filterSelectControl = document.getElementById("statistics_filter"); filterSelectControl.addEventListener("change", async (event) => { const filter = event.target.value; - drawGraph(filter); }); }