/** * webtrees: online genealogy * Copyright (C) 2019 webtrees development team * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ "use strict"; const GOOGLE_CHARTS_LIB = "https://www.gstatic.com/charts/loader.js"; /** * Statistics class. */ class Statistics { /** * Constructor. * * @returns {Statistics} */ constructor() { // Create singleton instance if (!Statistics.instance) { Statistics.instance = this; this.callbacks = []; this.initialized = false; this.loading = false; } return Statistics.instance; } /** * Initializes the google chart engine. Loads the chart lib only once. * * @param {String} locale Locale, e.g. en, de, ... */ init(locale) { if (this.loading || this.initialized) { return; } var that = this; Promise.all([ this.load(GOOGLE_CHARTS_LIB) ]).then(function () { google.charts.load( "current", { "packages": [ "corechart", "geochart", "bar" ], "language": locale, // Note: you will need to get a mapsApiKey for your project. // See: https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings "mapsApiKey": "" } ); google.charts.setOnLoadCallback(function () { that.callbacks.forEach(function(element) { element(); }); }); that.initialized = true; }).catch(function (error) { console.log(error); }); } /** * Dynamically loads a script by the given URL. * * @param {String} url * * @returns {Promise} */ load(url) { if (this.loading) { return; } this.loading = true; return new Promise(function (resolve, reject) { let script = document.createElement("script"); script.async = true; script.onload = function () { resolve(url); } script.onerror = function () { reject(url); } script.src = url; document.body.appendChild(script); }); } /** * Adds the given callback method to the callback stack or add it directly to * the google charts interface once the chart engine is up and running. * * @param {Function} callback */ addCallback(callback) { if (this.initialized) { google.charts.setOnLoadCallback(callback); } else { this.callbacks.push(callback); } $(window).resize(function () { callback(); }); } /** * Draws a google chart. * * @param {String} containerId * @param {String} chartType * @param {Array} dataTable * @param {Object} options */ drawChart(containerId, chartType, data, options) { let dataTable = google.visualization.arrayToDataTable(data); let wrapper = new google.visualization.ChartWrapper({ chartType: chartType, dataTable: dataTable, options: options, containerId: containerId }); wrapper.draw(); } /** * Draws a pie chart. * * @param {String} elementId The element id of the HTML element the chart is rendered too * @param {Array} data The chart data array * @param {Object} options The chart specific options to overwrite the default ones */ drawPieChart(elementId, data, options) { // Default chart options let defaults = { title: "", height: "100%", width: "100%", pieStartAngle: 0, pieSliceText: "none", pieSliceTextStyle: { color: "#777" }, pieHole: 0.4, // Donut //is3D: true, // 3D (not together with pieHole) legend: { alignment: "center", // Flickers on mouseover :( labeledValueText: "value", position: "labeled" }, chartArea: { left: 0, top: "5%", height: "90%", width: "100%" }, tooltip: { trigger: "none", text: "both" }, backgroundColor: "transparent", colors: [] }; // Merge default with provided options options = Object.assign(defaults, options); // Create and draw the chart this.drawChart(elementId, "PieChart", data, options); } /** * Draws a column chart. * * @param {String} elementId The element id of the HTML element the chart is rendered too * @param {Array} data The chart data array * @param {Object} options The chart specific options to overwrite the default ones */ drawColumnChart(elementId, data, options) { // Default chart options let defaults = { title: "", subtitle: "", titleTextStyle: { color: "#757575", fontName: "Roboto", fontSize: "16px", bold: false, italic: false }, height: "100%", width: "100%", vAxis: { title: "" }, hAxis: { title: "" }, legend: { position: "none" }, backgroundColor: "transparent" }; // Merge default with provided options options = Object.assign(defaults, options); // Create and draw the chart this.drawChart(elementId, "ColumnChart", data, options); } /** * Draws a combo chart. * * @param {String} elementId The element id of the HTML element the chart is rendered too * @param {Array} data The chart data array * @param {Object} options The chart specific options to overwrite the default ones */ drawComboChart(elementId, data, options) { // Default chart options let defaults = { title: "", subtitle: "", titleTextStyle: { color: "#757575", fontName: "Roboto", fontSize: "16px", bold: false, italic: false }, height: "100%", width: "100%", vAxis: { title: "" }, hAxis: { title: "" }, legend: { position: "none" }, seriesType: "bars", series: { 2: { type: "line" } }, colors: [], backgroundColor: "transparent" }; // Merge default with provided options options = Object.assign(defaults, options); // Create and draw the chart this.drawChart(elementId, "ComboChart", data, options); } /** * Draws a geo chart. * * @param {String} elementId The element id of the HTML element the chart is rendered too * @param {Array} data The chart data array * @param {Object} options The chart specific options to overwrite the default ones */ drawGeoChart(elementId, data, options) { // Default chart options let defaults = { title: "", subtitle: "", height: "100%", width: "100%" }; // Merge default with provided options options = Object.assign(defaults, options); // Create and draw the chart this.drawChart(elementId, "GeoChart", data, options); } } // Create singleton instance of class const statistics = new Statistics();