kopia lustrzana https://github.com/magicbug/Cloudlog
[Statistics] Changed from Google Charts to Chart.js
rodzic
6e87211fde
commit
4e17281a98
|
@ -2,7 +2,6 @@
|
|||
|
||||
class Statistics extends CI_Controller {
|
||||
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->load->model('user_model');
|
||||
|
@ -13,30 +12,7 @@ class Statistics extends CI_Controller {
|
|||
} else {
|
||||
redirect('user/login');
|
||||
}
|
||||
}
|
||||
|
||||
// Database connections
|
||||
$this->load->model('logbook_model');
|
||||
|
||||
// Store info
|
||||
$data['todays_qsos'] = $this->logbook_model->todays_qsos();
|
||||
$data['total_qsos'] = $this->logbook_model->total_qsos();
|
||||
$data['month_qsos'] = $this->logbook_model->month_qsos();
|
||||
$data['year_qsos'] = $this->logbook_model->year_qsos();
|
||||
|
||||
$data['total_ssb'] = $this->logbook_model->total_ssb();
|
||||
$data['total_cw'] = $this->logbook_model->total_cw();
|
||||
$data['total_fm'] = $this->logbook_model->total_fm();
|
||||
$data['total_digi'] = $this->logbook_model->total_digi();
|
||||
|
||||
$data['total_bands'] = $this->logbook_model->total_bands();
|
||||
|
||||
$data['total_sat'] = $this->logbook_model->total_sat();
|
||||
|
||||
$data['page_title'] = "Statistics";
|
||||
|
||||
$data['totals_year'] = $this->logbook_model->totals_year();
|
||||
|
||||
}
|
||||
// Render User Interface
|
||||
|
||||
// Set Page Title
|
||||
|
@ -91,4 +67,83 @@ class Statistics extends CI_Controller {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public function get_year() {
|
||||
$this->load->model('logbook_model');
|
||||
|
||||
// get data
|
||||
$totals_year = $this->logbook_model->totals_year();
|
||||
|
||||
$yearstats = array();
|
||||
|
||||
$i = 0;
|
||||
if ($totals_year) {
|
||||
foreach($totals_year->result() as $qso_numbers) {
|
||||
$yearstats[$i]['year'] = $qso_numbers->year;
|
||||
$yearstats[$i++]['total'] = $qso_numbers->total;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($yearstats);
|
||||
}
|
||||
|
||||
public function get_mode() {
|
||||
$this->load->model('logbook_model');
|
||||
|
||||
$modestats = array();
|
||||
|
||||
$i = 0;
|
||||
$modestats[$i]['mode'] = 'ssb';
|
||||
$modestats[$i++]['total'] = $this->logbook_model->total_ssb();
|
||||
$modestats[$i]['mode'] = 'cw';
|
||||
$modestats[$i++]['total'] = $this->logbook_model->total_cw();
|
||||
$modestats[$i]['mode'] = 'fm';
|
||||
$modestats[$i++]['total'] = $this->logbook_model->total_fm();
|
||||
$modestats[$i]['mode'] = 'digi';
|
||||
$modestats[$i]['total'] = $this->logbook_model->total_digi();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
echo json_encode($modestats);
|
||||
}
|
||||
|
||||
public function get_band() {
|
||||
$this->load->model('logbook_model');
|
||||
|
||||
$bandstats = array();
|
||||
|
||||
$total_bands = $this->logbook_model->total_bands();
|
||||
|
||||
$i = 0;
|
||||
|
||||
if ($total_bands) {
|
||||
foreach($total_bands->result() as $qso_numbers) {
|
||||
$bandstats[$i]['band'] = $qso_numbers->band;
|
||||
$bandstats[$i++]['count'] = $qso_numbers->count;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($bandstats);
|
||||
}
|
||||
|
||||
public function get_sat() {
|
||||
$this->load->model('logbook_model');
|
||||
|
||||
$satstats = array();
|
||||
|
||||
$total_sat = $this->logbook_model->total_sat();
|
||||
$i = 0;
|
||||
|
||||
if ($total_sat) {
|
||||
foreach($total_sat->result() as $qso_numbers) {
|
||||
$satstats[$i]['sat'] = $qso_numbers->COL_SAT_NAME;
|
||||
$satstats[$i++]['count'] = $qso_numbers->count;
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($satstats);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1422,12 +1422,13 @@ class Logbook_model extends CI_Model {
|
|||
if (!$logbooks_locations_array) {
|
||||
return null;
|
||||
}
|
||||
$mode[] = 'SSB';
|
||||
$mode[] = 'LSB';
|
||||
$mode[] = 'USB';
|
||||
|
||||
$this->db->select('COUNT( * ) as count', FALSE);
|
||||
$this->db->where_in('station_id', $logbooks_locations_array);
|
||||
$this->db->where('COL_MODE', 'SSB');
|
||||
$this->db->or_where('COL_MODE', 'LSB');
|
||||
$this->db->or_where('COL_MODE', 'USB');
|
||||
$this->db->where_in('COL_MODE', $mode);
|
||||
|
||||
$query = $this->db->get($this->config->item('table_name'));
|
||||
|
||||
|
@ -1558,7 +1559,7 @@ class Logbook_model extends CI_Model {
|
|||
return null;
|
||||
}
|
||||
|
||||
$this->db->select('DISTINCT (COL_BAND) AS band, count( * ) AS count', FALSE);
|
||||
$this->db->select('COL_BAND AS band, count( * ) AS count', FALSE);
|
||||
$this->db->where_in('station_id', $logbooks_locations_array);
|
||||
$this->db->group_by('band');
|
||||
$this->db->order_by('count', 'DESC');
|
||||
|
|
|
@ -40,6 +40,12 @@ function load_was_map() {
|
|||
|
||||
</script>
|
||||
|
||||
<?php if ($this->uri->segment(1) == "statistics") { ?>
|
||||
<script type="text/javascript" src="<?php echo base_url(); ?>assets/js/chart.js"></script>
|
||||
<script type="text/javascript" src="<?php echo base_url(); ?>assets/js/chartjs-plugin-piechart-outlabels.js"></script>
|
||||
<script type="text/javascript" src="<?php echo base_url(); ?>assets/js/sections/statistics.js"></script>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($this->uri->segment(1) == "adif") { ?>
|
||||
<!-- Javascript used for ADIF Import and Export Areas -->
|
||||
<script type="text/javascript" src="<?php echo base_url(); ?>assets/js/moment.min.js"></script>
|
||||
|
|
|
@ -1,204 +1,12 @@
|
|||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript">
|
||||
<style>
|
||||
/*canvas{
|
||||
margin: 0 auto;
|
||||
}*/
|
||||
|
||||
// Load the Visualization API and the piechart package.
|
||||
google.load('visualization', '1', {'packages':['corechart']});
|
||||
|
||||
// Set a callback to run when the Google Visualization API is loaded.
|
||||
<?php if (($total_ssb != null) && ($total_cw != null) && ($total_fm != null) && ($total_digi != null)) { ?>
|
||||
google.setOnLoadCallback(drawModeChart);
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($total_bands) { ?>
|
||||
google.setOnLoadCallback(drawBandChart);
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($total_sat && $total_sat->num_rows() != 0) { ?>
|
||||
google.setOnLoadCallback(drawSatChart);
|
||||
<?php } ?>
|
||||
|
||||
|
||||
// Callback that creates and populates a data table,
|
||||
// instantiates the pie chart, passes in the data and
|
||||
// draws it.
|
||||
function drawModeChart() {
|
||||
|
||||
// Create our data table.
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Topping');
|
||||
data.addColumn('number', 'Slices');
|
||||
data.addRows([
|
||||
['SSB', <?php echo $total_ssb==null?0:$total_ssb; ?>],
|
||||
['CW', <?php echo $total_cw==null?0:$total_cw; ?>],
|
||||
['FM', <?php echo $total_fm==null?0:$total_fm; ?>],
|
||||
['Digi', <?php echo $total_digi==null?0:$total_digi; ?>],
|
||||
]);
|
||||
|
||||
var color = ifDarkModeThemeReturn('white');
|
||||
var options = {
|
||||
title: 'Modes',
|
||||
width: 900,
|
||||
height: 440,
|
||||
backgroundColor: getBodyBackground(),
|
||||
legendTextStyle: {
|
||||
color: color
|
||||
},
|
||||
titleTextStyle: {
|
||||
fontSize: 20,
|
||||
color: color
|
||||
},
|
||||
hAxisTextStyle: {
|
||||
color: color
|
||||
},
|
||||
vAxisTextStyle: {
|
||||
color: color
|
||||
}
|
||||
};
|
||||
|
||||
// Instantiate and draw our chart, passing in some options.
|
||||
var chart = new google.visualization.PieChart(document.getElementById('modechart_div'));
|
||||
chart.draw(data, options);
|
||||
#modeChart, #bandChart, #satChart{
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
function drawBandChart() {
|
||||
|
||||
// Create our data table.
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Topping');
|
||||
data.addColumn('number', 'Slices');
|
||||
data.addRows([
|
||||
<?php
|
||||
if ($total_bands) {
|
||||
|
||||
foreach($total_bands->result() as $row) { ?>
|
||||
['<?php echo $row->band; ?>', <?php echo $row->count; ?>],
|
||||
<?php }
|
||||
}
|
||||
|
||||
?>
|
||||
]);
|
||||
|
||||
var color = ifDarkModeThemeReturn('white');
|
||||
var options = {
|
||||
title: 'Bands',
|
||||
width: 900,
|
||||
height: 440,
|
||||
backgroundColor: getBodyBackground(),
|
||||
legendTextStyle: {
|
||||
color: color
|
||||
},
|
||||
titleTextStyle: {
|
||||
fontSize: 20,
|
||||
color: color
|
||||
},
|
||||
hAxisTextStyle: {
|
||||
color: color
|
||||
},
|
||||
vAxisTextStyle: {
|
||||
color: color
|
||||
}
|
||||
};
|
||||
|
||||
// Instantiate and draw our chart, passing in some options.
|
||||
var chart = new google.visualization.PieChart(document.getElementById('bandchart_div'));
|
||||
chart.draw(data, options);
|
||||
}
|
||||
|
||||
function drawSatChart() {
|
||||
// Create our data table.
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Topping');
|
||||
data.addColumn('number', 'Slices');
|
||||
data.addRows([
|
||||
<?php
|
||||
if ($total_sat) {
|
||||
foreach($total_sat->result() as $row1) { ?>
|
||||
<?php if($row1->COL_SAT_NAME != null) { ?>
|
||||
['<?php echo $row1->COL_SAT_NAME; ?>', <?php echo $row1->count; ?>],
|
||||
<?php } ?>
|
||||
<?php }
|
||||
}?>
|
||||
]);
|
||||
|
||||
var color = ifDarkModeThemeReturn('white');
|
||||
var options = {
|
||||
width: 900,
|
||||
height: 440,
|
||||
backgroundColor: getBodyBackground(),
|
||||
legendTextStyle: {
|
||||
color: color
|
||||
},
|
||||
titleTextStyle: {
|
||||
fontSize: 20,
|
||||
color: color
|
||||
},
|
||||
hAxisTextStyle: {
|
||||
color: color
|
||||
},
|
||||
vAxisTextStyle: {
|
||||
color: color
|
||||
}
|
||||
};
|
||||
|
||||
// Instantiate and draw our chart, passing in some options.
|
||||
var chart = new google.visualization.PieChart(document.getElementById('satchart_div'));
|
||||
chart.draw(data, options);
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
<?php if ($totals_year) { ?>
|
||||
google.setOnLoadCallback(barchart);
|
||||
<?php } ?>
|
||||
function barchart() {
|
||||
var data = google.visualization.arrayToDataTable([
|
||||
['Year', 'QSOs'],
|
||||
<?php
|
||||
if ($totals_year) {
|
||||
foreach($totals_year->result() as $qso_numbers) { ?>
|
||||
['<?php echo $qso_numbers->year; ?>', <?php echo $qso_numbers->total; ?>],
|
||||
<?php }
|
||||
}
|
||||
?>
|
||||
]);
|
||||
|
||||
var color = ifDarkModeThemeReturn('white');
|
||||
var options = {
|
||||
title: 'Total QSOs Per Year',
|
||||
width: 900,
|
||||
height: 500,
|
||||
backgroundColor: getBodyBackground(),
|
||||
legendTextStyle: {
|
||||
color: color
|
||||
},
|
||||
titleTextStyle: {
|
||||
fontSize: 20,
|
||||
color: color
|
||||
},
|
||||
hAxis: {
|
||||
title: 'Year',
|
||||
titleTextStyle: {
|
||||
color: color
|
||||
},
|
||||
textStyle: {
|
||||
color: color
|
||||
}
|
||||
},
|
||||
vAxis: {
|
||||
title: 'QSOs',
|
||||
titleTextStyle: {
|
||||
color: color
|
||||
},
|
||||
textStyle: {
|
||||
color: color
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var chart = new google.visualization.ColumnChart(document.getElementById('totals_year'));
|
||||
chart.draw(data, options);
|
||||
}
|
||||
</script>
|
||||
|
||||
</style>
|
||||
<div class="container statistics">
|
||||
|
||||
<h2>
|
||||
|
@ -207,27 +15,40 @@
|
|||
</h2>
|
||||
|
||||
<br>
|
||||
|
||||
<?php if ($total_sat && $total_sat->num_rows() != 0) { ?>
|
||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">General</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="satellite-tab" data-toggle="tab" href="#satellite" role="tab" aria-controls="satellite" aria-selected="false">Satellites</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php } ?>
|
||||
<div hidden class="tabs">
|
||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">General</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="satellite-tab" data-toggle="tab" href="#satellite" role="tab" aria-controls="satellite" aria-selected="false">Satellites</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
|
||||
<div id="totals_year"></div>
|
||||
<div id="modechart_div"></div>
|
||||
<div id="bandchart_div"></div>
|
||||
<div class="years">
|
||||
</div>
|
||||
<div class="mode">
|
||||
</div>
|
||||
<div class="band">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="satellite" role="tabpanel" aria-labelledby="satellite-tab">
|
||||
<div id="satchart_div"></div>
|
||||
<br/>
|
||||
<div style="display: flex;" id="satContainer"><div style="flex: 1;"><canvas id="satChart" width="500" height="500"></canvas></div><div style="flex: 1;" id="satTable">
|
||||
|
||||
<table style="width:100%" class="sattable table table-sm table-bordered table-hover table-striped table-condensed text-center"><thead>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>Satellite</td>
|
||||
<td># of QSO's worked</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,792 @@
|
|||
/*!
|
||||
* @energiency/chartjs-plugin-piechart-outlabels v1.3.1
|
||||
* http://www.chartjs.org
|
||||
* (c) 2017-2022 @energiency/chartjs-plugin-piechart-outlabels contributors
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('chart.js'), require('chart.js/helpers')) :
|
||||
typeof define === 'function' && define.amd ? define(['chart.js', 'chart.js/helpers'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ChartPieChartOutlabels = factory(global.Chart, global.Chart.helpers));
|
||||
})(this, (function (chart_js, helpers) { 'use strict';
|
||||
|
||||
/**
|
||||
* @module Options
|
||||
*/
|
||||
|
||||
var customDefaults = {
|
||||
|
||||
PLUGIN_KEY: '$outlabels',
|
||||
|
||||
/**
|
||||
* The color used to draw the background of the label rect.
|
||||
* @member {String|Array|Function|null}
|
||||
* @default null (adaptive background)
|
||||
*/
|
||||
backgroundColor: function(context) {
|
||||
return context.dataset.backgroundColor;
|
||||
},
|
||||
|
||||
/**
|
||||
* The color used to draw the border of the label rect.
|
||||
* @member {String|Array|Function|null}
|
||||
* @default null (adaptive border color)
|
||||
*/
|
||||
borderColor: function(context) {
|
||||
return context.dataset.backgroundColor;
|
||||
},
|
||||
|
||||
/**
|
||||
* The color used to draw the line between label and arc of the chart.
|
||||
* @member {String|Array|Function|null}
|
||||
* @default null (adaptive line color)
|
||||
*/
|
||||
lineColor: function(context) {
|
||||
return context.dataset.backgroundColor;
|
||||
},
|
||||
|
||||
/**
|
||||
* The border radius used to add rounded corners to the label rect.
|
||||
* @member {Number|Array|Function}
|
||||
* @default 0 (not rounded)
|
||||
*/
|
||||
borderRadius: 0,
|
||||
|
||||
/**
|
||||
* The border width of the surrounding frame.
|
||||
* @member {Number|Array|Function}
|
||||
* @default 0 (no border)
|
||||
*/
|
||||
borderWidth: 0,
|
||||
|
||||
/**
|
||||
* The width (thickness) of the line between label and chart arc.
|
||||
* @member {Number|Array|Function}
|
||||
* @default 2
|
||||
*/
|
||||
lineWidth: 2,
|
||||
|
||||
/**
|
||||
* The color used to draw the label text.
|
||||
* @member {String|Array|Function}
|
||||
* @default white
|
||||
*/
|
||||
color: 'white',
|
||||
|
||||
/**
|
||||
* Whether to display labels global (boolean) or per data (function)
|
||||
* @member {Boolean|Array|Function}
|
||||
* @default true
|
||||
*/
|
||||
display: true,
|
||||
|
||||
/**
|
||||
* The font options used to draw the label text.
|
||||
* @member {Object|Array|Function}
|
||||
* @prop {Boolean} font.family - defaults to Chart.defaults.global.defaultFontFamily
|
||||
* @prop {Boolean} font.size - defaults to Chart.defaults.global.defaultFontSize
|
||||
* @prop {Boolean} font.style - defaults to Chart.defaults.global.defaultFontStyle
|
||||
* @prop {Boolean} font.weight - defaults to 'normal'
|
||||
* @prop {Boolean} font.maxSize - defaults to undefined (unlimited)
|
||||
* @prop {Boolean} font.minSize - defaults to undefined (unlimited)
|
||||
* @prop {Boolean} font.resizable - defaults to true
|
||||
* @default Chart.defaults.global.defaultFont.*
|
||||
*/
|
||||
font: {
|
||||
family: undefined,
|
||||
size: undefined,
|
||||
style: undefined,
|
||||
weight: null,
|
||||
maxSize: null,
|
||||
minSize: null,
|
||||
resizable: true,
|
||||
},
|
||||
|
||||
/**
|
||||
* The line height (in pixel) to use for multi-lines labels.
|
||||
* @member {Number|Array|Function|undefined}
|
||||
* @default 1.2
|
||||
*/
|
||||
lineHeight: 1.2,
|
||||
|
||||
|
||||
/**
|
||||
* The padding (in pixels) to apply between the text and the surrounding frame.
|
||||
* @member {Number|Object|Array|Function}
|
||||
* @prop {Number} padding.top - Space above the text.
|
||||
* @prop {Number} padding.right - Space on the right of the text.
|
||||
* @prop {Number} padding.bottom - Space below the text.
|
||||
* @prop {Number} padding.left - Space on the left of the text.
|
||||
* @default 4 (all values)
|
||||
*/
|
||||
padding: {
|
||||
top: 2,
|
||||
right: 2,
|
||||
bottom: 2,
|
||||
left: 2
|
||||
},
|
||||
|
||||
/**
|
||||
* Text alignment for multi-lines labels ('left'|'right'|'start'|'center'|'end').
|
||||
* @member {String|Array|Function}
|
||||
* @default 'center'
|
||||
*/
|
||||
textAlign: 'center',
|
||||
|
||||
/**
|
||||
* The radius of distance where the label will be drawn
|
||||
* @member {Number|Array|Function|undefined}
|
||||
* @default 30
|
||||
*/
|
||||
stretch: 12,
|
||||
|
||||
/**
|
||||
* The length of the horizontal part of line between label and chart arc.
|
||||
* @member {Number}
|
||||
* @default 30
|
||||
*/
|
||||
horizontalStrechPad: 12,
|
||||
|
||||
/**
|
||||
* The text of the label.
|
||||
* @member {String}
|
||||
* @default '%l %p' (label name and value percentage)
|
||||
*/
|
||||
text: '%l %p',
|
||||
|
||||
/**
|
||||
* The max level of zoom (out) for pie/doughnut chart in percent.
|
||||
* @member {Number}
|
||||
* @default 50 (%)
|
||||
*/
|
||||
maxZoomOutPercentage: 50,
|
||||
|
||||
/**
|
||||
* The count of numbers after the point separator for float values of percent property
|
||||
* @member {Number}
|
||||
* @default 1
|
||||
*/
|
||||
percentPrecision: 1,
|
||||
|
||||
/**
|
||||
* The count of numbers after the point separator for float values of value property
|
||||
* @member {Number}
|
||||
* @default 3
|
||||
*/
|
||||
valuePrecision: 3
|
||||
};
|
||||
|
||||
var positioners = {
|
||||
center: function(arc, stretch) {
|
||||
var angle = (arc.startAngle + arc.endAngle) / 2;
|
||||
var cosA = Math.cos(angle);
|
||||
var sinA = Math.sin(angle);
|
||||
var d = arc.outerRadius;
|
||||
|
||||
var stretchedD = d + stretch;
|
||||
return {
|
||||
x: arc.x + cosA * stretchedD,
|
||||
y: arc.y + sinA * stretchedD,
|
||||
d: stretchedD,
|
||||
arc: arc,
|
||||
anchor: {
|
||||
x: arc.x + cosA * d,
|
||||
y: arc.y + sinA * d,
|
||||
},
|
||||
copy: {
|
||||
x: arc.x + cosA * stretchedD,
|
||||
y: arc.y + sinA * stretchedD
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
moveFromAnchor: function(center, dist) {
|
||||
var arc = center.arc;
|
||||
var d = center.d;
|
||||
var angle = (arc.startAngle + arc.endAngle) / 2;
|
||||
var cosA = Math.cos(angle);
|
||||
var sinA = Math.sin(angle);
|
||||
|
||||
d += dist;
|
||||
|
||||
return {
|
||||
x: arc.x + cosA * d,
|
||||
y: arc.y + sinA * d,
|
||||
d: d,
|
||||
arc: arc,
|
||||
anchor: center.anchor,
|
||||
copy: {
|
||||
x: arc.x + cosA * d,
|
||||
y: arc.y + sinA * d
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function toFontString(font) {
|
||||
if (!font || helpers.isNullOrUndef(font.size) || helpers.isNullOrUndef(font.family)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (font.style ? font.style + ' ' : '')
|
||||
+ (font.weight ? font.weight + ' ' : '')
|
||||
+ font.size + 'px '
|
||||
+ font.family;
|
||||
}
|
||||
|
||||
function textSize(ctx, lines, font) {
|
||||
var items = [].concat(lines);
|
||||
var ilen = items.length;
|
||||
var prev = ctx.font;
|
||||
var width = 0;
|
||||
var i;
|
||||
|
||||
ctx.font = font.string;
|
||||
|
||||
for (i = 0; i < ilen; ++i) {
|
||||
width = Math.max(ctx.measureText(items[i]).width, width);
|
||||
}
|
||||
|
||||
ctx.font = prev;
|
||||
|
||||
return {
|
||||
height: ilen * font.lineHeight,
|
||||
width: width
|
||||
};
|
||||
}
|
||||
|
||||
function adaptTextSizeToHeight(height, minimum, maximum) {
|
||||
var size = (height / 100) * 2.5;
|
||||
if (minimum && size < minimum) {
|
||||
return minimum;
|
||||
}
|
||||
if (maximum && size > maximum) {
|
||||
return maximum;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
function parseFont(value, height) {
|
||||
var size = helpers.valueOrDefault(value.size, chart_js.Chart.defaults.defaultFontSize);
|
||||
|
||||
if (value.resizable) {
|
||||
size = adaptTextSizeToHeight(height, value.minSize, value.maxSize);
|
||||
}
|
||||
|
||||
var font = {
|
||||
family: helpers.valueOrDefault(value.family, chart_js.Chart.defaults.defaultFontFamily),
|
||||
lineHeight: helpers.toLineHeight(value.lineHeight, size),
|
||||
size: size,
|
||||
style: helpers.valueOrDefault(value.style, chart_js.Chart.defaults.defaultFontStyle),
|
||||
weight: helpers.valueOrDefault(value.weight, null),
|
||||
string: ''
|
||||
};
|
||||
|
||||
font.string = toFontString(font);
|
||||
return font;
|
||||
}
|
||||
|
||||
var PLUGIN_KEY$1 = customDefaults.PLUGIN_KEY;
|
||||
|
||||
var classes = {
|
||||
OutLabel: function(chart, index, ctx, config, context) {
|
||||
// Check whether the label should be displayed
|
||||
if (!helpers.resolve([config.display, true], context, index)) {
|
||||
throw new Error('Label display property is set to false.');
|
||||
}
|
||||
|
||||
// Init text
|
||||
var value = context.dataset.data[index];
|
||||
var label = context.labels[index];
|
||||
var text = helpers.resolve([config.text, customDefaults.text], context, index);
|
||||
/* Replace label marker */
|
||||
text = text.replace(/%l/gi, label);
|
||||
|
||||
/* Replace value marker with possible precision value */
|
||||
(text.match(/%v\.?(\d*)/gi) || []).map(function(val) {
|
||||
var prec = val.replace(/%v\./gi, '');
|
||||
if (prec.length) {
|
||||
return +prec;
|
||||
}
|
||||
return config.valuePrecision || customDefaults.valuePrecision;
|
||||
}).forEach(function(val) {
|
||||
text = text.replace(/%v\.?(\d*)/i, value.toFixed(val));
|
||||
});
|
||||
|
||||
/* Replace percent marker with possible precision value */
|
||||
(text.match(/%p\.?(\d*)/gi) || []).map(function(val) {
|
||||
var prec = val.replace(/%p\./gi, '');
|
||||
if (prec.length) {
|
||||
return +prec;
|
||||
}
|
||||
return config.percentPrecision || customDefaults.percentPrecision;
|
||||
}).forEach(function(val) {
|
||||
text = text.replace(/%p\.?(\d*)/i, (context.percent * 100).toFixed(val) + '%');
|
||||
});
|
||||
|
||||
// Count lines
|
||||
var lines = text.match(/[^\r\n]+/g) || [];
|
||||
|
||||
// Remove unnecessary spaces
|
||||
for (var i = 0; i < lines.length; ++i) {
|
||||
lines[i] = lines[i].trim();
|
||||
}
|
||||
|
||||
/* ===================== CONSTRUCTOR ==================== */
|
||||
this.init = function(text, lines) {
|
||||
// If everything ok -> begin initializing
|
||||
this.encodedText = config.text;
|
||||
this.text = text;
|
||||
this.lines = lines;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.ctx = ctx;
|
||||
|
||||
// Init style
|
||||
this.style = {
|
||||
backgroundColor: helpers.resolve([config.backgroundColor, customDefaults.backgroundColor, 'black'], context, index),
|
||||
borderColor: helpers.resolve([config.borderColor, customDefaults.borderColor, 'black'], context, index),
|
||||
borderRadius: helpers.resolve([config.borderRadius, 0], context, index),
|
||||
borderWidth: helpers.resolve([config.borderWidth, 0], context, index),
|
||||
lineWidth: helpers.resolve([config.lineWidth, 2], context, index),
|
||||
lineColor: helpers.resolve([config.lineColor, customDefaults.lineColor, 'black'], context, index),
|
||||
color: helpers.resolve([config.color, 'white'], context, index),
|
||||
font: parseFont(helpers.resolve([config.font, {resizable: true}]), ctx.canvas.style.height.slice(0, -2)),
|
||||
padding: helpers.toPadding(helpers.resolve([config.padding, 0], context, index)),
|
||||
textAlign: helpers.resolve([config.textAlign, 'left'], context, index),
|
||||
};
|
||||
|
||||
this.stretch = helpers.resolve([config.stretch, customDefaults.stretch], context, index);
|
||||
this.horizontalStrechPad = helpers.resolve([config.horizontalStrechPad, customDefaults.horizontalStrechPad], context, index);
|
||||
this.size = textSize(ctx, this.lines, this.style.font);
|
||||
|
||||
this.offsetStep = this.size.width / 20;
|
||||
this.offset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
this.predictedOffset = this.offset;
|
||||
|
||||
/*var angle = -((el._model.startAngle + el._model.endAngle) / 2) / (Math.PI);
|
||||
var val = Math.abs(angle - Math.trunc(angle));
|
||||
|
||||
if (val > 0.45 && val < 0.55) {
|
||||
this.predictedOffset.x = 0;
|
||||
} else if (angle <= 0.45 && angle >= -0.45) {
|
||||
this.predictedOffset.x = this.size.width / 2;
|
||||
} else if (angle >= -1.45 && angle <= -0.55) {
|
||||
this.predictedOffset.x = -this.size.width / 2;
|
||||
}*/
|
||||
};
|
||||
|
||||
this.init(text, lines);
|
||||
|
||||
/* COMPUTING RECTS PART */
|
||||
this.computeLabelRect = function() {
|
||||
var width = this.textRect.width + 2 * this.style.borderWidth + this.style.padding.left + this.style.padding.right;
|
||||
var height = this.textRect.height + 2 * this.style.borderWidth + this.style.padding.top + this.style.padding.bottom;
|
||||
|
||||
var x = this.textRect.x - this.style.borderWidth;
|
||||
var y = this.textRect.y - this.style.borderWidth;
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
isLeft: this.textRect.isLeft,
|
||||
isTop: this.textRect.isTop
|
||||
};
|
||||
};
|
||||
|
||||
this.computeTextRect = function() {
|
||||
const isLeft = this.center.x - this.center.anchor.x < 0;
|
||||
const isTop = this.center.y - this.center.anchor.y < 0;
|
||||
const shift = isLeft ? -(this.horizontalStrechPad + this.size.width) : this.horizontalStrechPad;
|
||||
return {
|
||||
x: this.center.x - this.style.padding.left + shift,
|
||||
y: this.center.y - (this.size.height / 2),
|
||||
width: this.size.width,
|
||||
height: this.size.height,
|
||||
isLeft,
|
||||
isTop
|
||||
};
|
||||
};
|
||||
|
||||
this.roundedRect = function (ctx, x, y, width, height, radius) {
|
||||
var TL, TR, BR, BL;
|
||||
|
||||
// Minimum horizontal value: half of the width
|
||||
var mH = r => Math.min(r, width / 2);
|
||||
// Minimum vertical value: half of the width
|
||||
var mV = r => Math.min(r, height / 2);
|
||||
|
||||
if (radius instanceof Array) {
|
||||
// [TL, TR, BR, BL]
|
||||
TL = radius[0];
|
||||
TR = radius[1];
|
||||
BR = radius[2];
|
||||
BL = radius[3];
|
||||
} else {
|
||||
TL = TR = BR = BL = radius;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.moveTo(x + mH(TL), y);
|
||||
ctx.lineTo(x + width - mH(TR), y);
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + mV(TR));
|
||||
ctx.lineTo(x + width, y + height - mV(BR));
|
||||
ctx.quadraticCurveTo(x + width, y + height, x + width - mH(BR), y + height);
|
||||
ctx.lineTo(x + mH(BL), y + height);
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - mV(BL));
|
||||
ctx.lineTo(x, y + mV(TL));
|
||||
ctx.quadraticCurveTo(x, y, x + mH(TL), y);
|
||||
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
this.getPoints = function() {
|
||||
return [
|
||||
{
|
||||
x: this.labelRect.x,
|
||||
y: this.labelRect.y
|
||||
},
|
||||
{
|
||||
x: this.labelRect.x + this.labelRect.width,
|
||||
y: this.labelRect.y
|
||||
},
|
||||
{
|
||||
x: this.labelRect.x + this.labelRect.width,
|
||||
y: this.labelRect.y + this.labelRect.height
|
||||
},
|
||||
{
|
||||
x: this.labelRect.x,
|
||||
y: this.labelRect.y + this.labelRect.height
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
this.containsPoint = function(point) {
|
||||
let offset = 5;
|
||||
|
||||
return this.labelRect.x - offset <= point.x && point.x <= this.labelRect.x + this.labelRect.width + offset
|
||||
&&
|
||||
this.labelRect.y - offset <= point.y && point.y <= this.labelRect.y + this.labelRect.height + offset;
|
||||
};
|
||||
|
||||
|
||||
/* ======================= DRAWING ======================= */
|
||||
// Draw label text
|
||||
this.drawText = function() {
|
||||
var align = this.style.textAlign;
|
||||
var font = this.style.font;
|
||||
var lh = font.lineHeight;
|
||||
var color = this.style.color;
|
||||
var ilen = this.lines.length;
|
||||
var x, y, idx;
|
||||
|
||||
if (!ilen || !color) {
|
||||
return;
|
||||
}
|
||||
|
||||
x = this.textRect.x;
|
||||
y = this.textRect.y + lh / 2;
|
||||
|
||||
if (align === 'center') {
|
||||
x += this.textRect.width / 2;
|
||||
} else if (align === 'end' || align === 'right') {
|
||||
x += this.textRect.width;
|
||||
}
|
||||
|
||||
this.ctx.font = this.style.font.string;
|
||||
this.ctx.fillStyle = color;
|
||||
this.ctx.textAlign = align;
|
||||
this.ctx.textBaseline = 'middle';
|
||||
|
||||
for (idx = 0; idx < ilen; ++idx) {
|
||||
this.ctx.fillText(
|
||||
this.lines[idx],
|
||||
Math.round(x) + this.style.padding.left,
|
||||
Math.round(y),
|
||||
Math.round(this.textRect.width)
|
||||
);
|
||||
y += lh;
|
||||
}
|
||||
};
|
||||
|
||||
this.ccw = function(A, B, C) {
|
||||
return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x);
|
||||
};
|
||||
|
||||
this.intersects = function(A, B, C, D) {
|
||||
return this.ccw(A, C, D) !== this.ccw(B, C, D) && this.ccw(A, B, C) !== this.ccw(A, B, D);
|
||||
};
|
||||
|
||||
// Draw label box
|
||||
this.drawLabel = function() {
|
||||
ctx.beginPath();
|
||||
this.roundedRect(
|
||||
this.ctx,
|
||||
Math.round(this.labelRect.x),
|
||||
Math.round(this.labelRect.y),
|
||||
Math.round(this.labelRect.width),
|
||||
Math.round(this.labelRect.height),
|
||||
this.style.borderRadius
|
||||
);
|
||||
this.ctx.closePath();
|
||||
|
||||
if (this.style.backgroundColor) {
|
||||
this.ctx.fillStyle = this.style.backgroundColor || 'black';
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
if (this.style.borderColor && this.style.borderWidth) {
|
||||
this.ctx.strokeStyle = this.style.borderColor;
|
||||
this.ctx.lineWidth = this.style.borderWidth;
|
||||
this.ctx.lineJoin = 'miter';
|
||||
this.ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
this.drawLine = function() {
|
||||
if (!this.lines.length) {
|
||||
return;
|
||||
}
|
||||
this.ctx.save();
|
||||
|
||||
this.ctx.strokeStyle = this.style.lineColor;
|
||||
this.ctx.lineWidth = this.style.lineWidth;
|
||||
this.ctx.lineJoin = 'miter';
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(this.center.anchor.x, this.center.anchor.y);
|
||||
this.ctx.lineTo(this.center.copy.x, this.center.copy.y);
|
||||
this.ctx.stroke();
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(this.center.copy.x, this.center.copy.y);
|
||||
const xOffset = this.textRect.width + this.style.padding.width;
|
||||
const intersect = this.intersects(this.textRect, {
|
||||
x: this.textRect.x + this.textRect.width,
|
||||
y: this.textRect.y + this.textRect.height,
|
||||
}, this.center.copy, {
|
||||
x: this.textRect.x,
|
||||
y: this.textRect.y + this.textRect.height / 2
|
||||
});
|
||||
this.ctx.lineTo(this.textRect.x + (intersect ? xOffset : 0), this.textRect.y + this.textRect.height / 2);
|
||||
this.ctx.stroke();
|
||||
this.ctx.restore();
|
||||
};
|
||||
|
||||
this.draw = function() {
|
||||
if (chart.getDataVisibility(index)) {
|
||||
this.drawLabel();
|
||||
this.drawText();
|
||||
this.drawLine();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// eslint-disable-next-line max-statements
|
||||
this.update = function(view, elements, max) {
|
||||
this.center = positioners.center(view, this.stretch);
|
||||
this.moveLabelToOffset();
|
||||
|
||||
this.center.x += this.offset.x;
|
||||
this.center.y += this.offset.y;
|
||||
|
||||
var valid = false;
|
||||
|
||||
while (!valid) {
|
||||
this.textRect = this.computeTextRect();
|
||||
this.labelRect = this.computeLabelRect();
|
||||
|
||||
var rectPoints = this.getPoints();
|
||||
|
||||
valid = true;
|
||||
|
||||
for (var e = 0; e < max; ++e) {
|
||||
var element = elements[e][PLUGIN_KEY$1];
|
||||
if (!element || !chart.getDataVisibility(index)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var elPoints = element.getPoints();
|
||||
|
||||
for (var p = 0; p < rectPoints.length; ++p) {
|
||||
if (element.containsPoint(rectPoints[p])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.containsPoint(elPoints[p])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
this.center = positioners.moveFromAnchor(this.center, 1);
|
||||
this.center.x += this.offset.x;
|
||||
this.center.y += this.offset.y;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.moveLabelToOffset = function() {
|
||||
if (this.predictedOffset.x <= 0 && this.offset.x > this.predictedOffset.x) {
|
||||
this.offset.x -= this.offsetStep;
|
||||
if (this.offset.x <= this.predictedOffset.x) {
|
||||
this.offset.x = this.predictedOffset.x;
|
||||
}
|
||||
} else if (this.predictedOffset.x >= 0 && this.offset.x < this.predictedOffset.x) {
|
||||
this.offset.x += this.offsetStep;
|
||||
if (this.offset.x >= this.predictedOffset.x) {
|
||||
this.offset.x = this.predictedOffset.x;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
chart_js.defaults.plugins.outlabels = customDefaults;
|
||||
|
||||
|
||||
var PLUGIN_KEY = customDefaults.PLUGIN_KEY;
|
||||
|
||||
function configure(dataset, options) {
|
||||
var override = dataset.outlabels;
|
||||
var config = {};
|
||||
|
||||
if (override === false) {
|
||||
return null;
|
||||
}
|
||||
if (override === true) {
|
||||
override = {};
|
||||
}
|
||||
|
||||
return Object.assign({}, config, options, override);
|
||||
|
||||
}
|
||||
|
||||
var plugin = {
|
||||
id: 'outlabels',
|
||||
resize: function(chart) {
|
||||
chart.sizeChanged = true;
|
||||
},
|
||||
afterUpdate: (chart) => {
|
||||
const ctrl = chart._metasets[0].controller;
|
||||
var meta = ctrl.getMeta();
|
||||
|
||||
var elements = meta.data || [];
|
||||
const rect = {
|
||||
x1: Infinity,
|
||||
x2: 0,
|
||||
y1: Infinity,
|
||||
y2: 0
|
||||
};
|
||||
elements.forEach((el, index) => {
|
||||
const outlabelPlugin = el[PLUGIN_KEY];
|
||||
if (!outlabelPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
outlabelPlugin.update(el, elements, index);
|
||||
const x = outlabelPlugin.labelRect.x + (!outlabelPlugin.labelRect.isLeft ? 0 : outlabelPlugin.labelRect.width);
|
||||
const y = outlabelPlugin.labelRect.y + (outlabelPlugin.labelRect.isTop ? 0 : outlabelPlugin.labelRect.height);
|
||||
if (x < rect.x1) {
|
||||
rect.x1 = x;
|
||||
}
|
||||
if (x > rect.x2) {
|
||||
rect.x2 = x;
|
||||
}
|
||||
if (y < rect.y1) {
|
||||
rect.y1 = y;
|
||||
}
|
||||
if (y > rect.y2) {
|
||||
rect.y2 = y;
|
||||
}
|
||||
});
|
||||
|
||||
var max = chart.options.maxZoomOutPercentage || customDefaults.maxZoomOutPercentage;
|
||||
const maxDeltas = [
|
||||
chart.chartArea.left - rect.x1,
|
||||
chart.chartArea.top - rect.y1,
|
||||
rect.x2 - chart.chartArea.right,
|
||||
rect.y2 - chart.chartArea.bottom
|
||||
];
|
||||
const diff = Math.max(...maxDeltas.filter(x => x > 0), 0);
|
||||
const percent = diff * 100 / ctrl.outerRadius;
|
||||
ctrl.outerRadius -= percent < max ? diff : max * 100 / ctrl.outerRadius;
|
||||
ctrl.innerRadius = ctrl.outerRadius / 2;
|
||||
|
||||
ctrl.updateElements(meta.data, 0, meta.data.length, 'resize');
|
||||
},
|
||||
afterDatasetUpdate: function(chart, args, options) {
|
||||
var labels = chart.config.data.labels;
|
||||
var dataset = chart.data.datasets[args.index];
|
||||
var config = configure(dataset, options);
|
||||
var display = config && config.display;
|
||||
var elements = args.meta.data || [];
|
||||
var ctx = chart.ctx;
|
||||
var el, label, percent, newLabel, context, i;
|
||||
ctx.save();
|
||||
|
||||
for (i = 0; i < elements.length; ++i) {
|
||||
el = elements[i];
|
||||
label = el[PLUGIN_KEY];
|
||||
percent = dataset.data[i] / args.meta.total;
|
||||
newLabel = null;
|
||||
|
||||
if (display && el && !el.hidden) {
|
||||
try {
|
||||
context = {
|
||||
chart: chart,
|
||||
dataIndex: i,
|
||||
dataset: dataset,
|
||||
labels: labels,
|
||||
datasetIndex: args.index,
|
||||
percent: percent
|
||||
};
|
||||
newLabel = new classes.OutLabel(chart, i, ctx, config, context);
|
||||
} catch (e) {
|
||||
newLabel = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
label && newLabel && !chart.sizeChanged &&
|
||||
(label.label === newLabel.label) && (label.encodedText === newLabel.encodedText)
|
||||
) {
|
||||
newLabel.offset = label.offset;
|
||||
}
|
||||
el[PLUGIN_KEY] = newLabel;
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
chart.sizeChanged = false;
|
||||
},
|
||||
afterDatasetDraw: function(chart, args) {
|
||||
var elements = args.meta.data || [];
|
||||
var ctx = chart.ctx;
|
||||
|
||||
elements.forEach((el, index) => {
|
||||
const outlabelPlugin = el[PLUGIN_KEY];
|
||||
if (!outlabelPlugin) {
|
||||
return;
|
||||
}
|
||||
outlabelPlugin.update(el, elements, index);
|
||||
outlabelPlugin.draw(ctx);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
return plugin;
|
||||
|
||||
}));
|
|
@ -0,0 +1,509 @@
|
|||
totalSatQsos();
|
||||
totalQsosPerYear();
|
||||
totalModeQsos();
|
||||
totalBandQsos();
|
||||
|
||||
// Needed for sattable header fix, will be squished without
|
||||
$("a[href='#satellite']").on('shown.bs.tab', function(e) {
|
||||
$(".sattable").DataTable().columns.adjust();
|
||||
});
|
||||
|
||||
function totalQsosPerYear() {
|
||||
// using this to change color of legend and label according to background color
|
||||
var color = ifDarkModeThemeReturn('white', 'grey');
|
||||
|
||||
$.ajax({
|
||||
url: base_url+'index.php/statistics/get_year',
|
||||
type: 'post',
|
||||
success: function (data) {
|
||||
if (data.length > 0) {
|
||||
|
||||
$(".years").append('<h2>Years</h2><div id="yearContainer"></div><div id="yearTable"></div>');
|
||||
$("#yearContainer").append("<canvas id=\"yearChart\" width=\"400\" height=\"100\"></canvas>");
|
||||
|
||||
// appending table to hold the data
|
||||
$("#yearTable").append('<table style="width:100%" class="yeartable table table-sm table-bordered table-hover table-striped table-condensed text-center"><thead>' +
|
||||
'<tr>' +
|
||||
'<td>#</td>' +
|
||||
'<td>Year</td>' +
|
||||
'<td># of QSO\'s worked </td>' +
|
||||
'</tr>' +
|
||||
'</thead>' +
|
||||
'<tbody></tbody></table>');
|
||||
|
||||
var labels = [];
|
||||
var dataQso = [];
|
||||
|
||||
var $myTable = $('.yeartable');
|
||||
var i = 1;
|
||||
|
||||
// building the rows in the table
|
||||
var rowElements = data.map(function (row) {
|
||||
|
||||
var $row = $('<tr></tr>');
|
||||
|
||||
var $iterator = $('<td></td>').html(i++);
|
||||
var $type = $('<td></td>').html(row.year);
|
||||
var $content = $('<td></td>').html(row.total);
|
||||
|
||||
$row.append($iterator, $type, $content);
|
||||
|
||||
return $row;
|
||||
});
|
||||
|
||||
// finally inserting the rows
|
||||
$myTable.append(rowElements);
|
||||
|
||||
$.each(data, function () {
|
||||
labels.push(this.year);
|
||||
dataQso.push(this.total);
|
||||
});
|
||||
|
||||
var ctx = document.getElementById("yearChart").getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Number of QSO\'s worked each year',
|
||||
data: dataQso,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 2,
|
||||
color: color
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
color: color
|
||||
}
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
color: color
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
labels: {
|
||||
color: color
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
$('.yeartable').DataTable({
|
||||
responsive: false,
|
||||
ordering: false,
|
||||
"scrollY": "170px",
|
||||
"scrollCollapse": true,
|
||||
"paging": false,
|
||||
"scrollX": true,
|
||||
bFilter: false,
|
||||
bInfo: false
|
||||
});
|
||||
|
||||
// using this to change color of csv-button if dark mode is chosen
|
||||
var background = $('body').css("background-color");
|
||||
|
||||
if (background != ('rgb(255, 255, 255)')) {
|
||||
$(".buttons-csv").css("color", "white");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function totalModeQsos() {
|
||||
// using this to change color of legend and label according to background color
|
||||
var color = ifDarkModeThemeReturn('white', 'grey');
|
||||
|
||||
$.ajax({
|
||||
url: base_url+'index.php/statistics/get_mode',
|
||||
type: 'post',
|
||||
success: function (data) {
|
||||
if (data.length > 0) {
|
||||
var labels = [];
|
||||
var dataQso = [];
|
||||
|
||||
$.each(data, function () {
|
||||
labels.push(this.mode.toUpperCase());
|
||||
dataQso.push(this.total);
|
||||
});
|
||||
|
||||
if (dataQso[0] === null && dataQso[1] === null && dataQso[2] === null && dataQso[3] === null) return;
|
||||
|
||||
$(".mode").append('<br /><div style="display: flex;" id="modeContainer"><h2>Modes</h2><div style="flex: 1;"><canvas id="modeChart" width="500" height="500"></canvas></div><div style="flex: 1;" id="modeTable"></div></div><br />');
|
||||
|
||||
// appending table to hold the data
|
||||
$("#modeTable").append('<table style="width:100%" class=\"modetable table table-sm table-bordered table-hover table-striped table-condensed text-center"><thead>' +
|
||||
'<tr>' +
|
||||
'<td>#</td>' +
|
||||
'<td>Mode</td>' +
|
||||
'<td># of QSO\'s worked </td>' +
|
||||
'</tr>' +
|
||||
'</thead>' +
|
||||
'<tbody></tbody></table>');
|
||||
|
||||
|
||||
var $myTable = $('.modetable');
|
||||
var i = 1;
|
||||
|
||||
// building the rows in the table
|
||||
var rowElements = data.map(function (row) {
|
||||
|
||||
var $row = $('<tr></tr>');
|
||||
|
||||
var $iterator = $('<td></td>').html(i++);
|
||||
var $type = $('<td></td>').html(row.mode.toUpperCase());
|
||||
var $content = $('<td></td>').html(row.total);
|
||||
|
||||
$row.append($iterator, $type, $content);
|
||||
|
||||
return $row;
|
||||
});
|
||||
|
||||
// finally inserting the rows
|
||||
$myTable.append(rowElements);
|
||||
|
||||
const COLORS = ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499"]
|
||||
|
||||
var ctx = document.getElementById("modeChart").getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'pie',
|
||||
plugins: [ChartPieChartOutlabels],
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Number of QSO\'s worked',
|
||||
data: dataQso,
|
||||
backgroundColor: ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499"],
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
}]
|
||||
},
|
||||
|
||||
options: {
|
||||
layout: {
|
||||
padding: 100
|
||||
},
|
||||
title: {
|
||||
color: color,
|
||||
fullSize: true,
|
||||
},
|
||||
responsive: false,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
labels: {
|
||||
boxWidth: 15,
|
||||
color: color,
|
||||
font: {
|
||||
size: 14,
|
||||
}
|
||||
},
|
||||
position: 'right',
|
||||
align: "middle"
|
||||
},
|
||||
outlabels: {
|
||||
backgroundColor: COLORS,
|
||||
borderColor: COLORS,
|
||||
borderRadius: 2, // Border radius of Label
|
||||
borderWidth: 2, // Thickness of border
|
||||
color: 'white',
|
||||
stretch: 45,
|
||||
padding: 0,
|
||||
font: {
|
||||
resizable: true,
|
||||
minSize: 15,
|
||||
maxSize: 25,
|
||||
family: Chart.defaults.font.family,
|
||||
size: Chart.defaults.font.size,
|
||||
style: Chart.defaults.font.style,
|
||||
lineHeight: Chart.defaults.font.lineHeight,
|
||||
},
|
||||
zoomOutPercentage: 100,
|
||||
textAlign: 'start',
|
||||
backgroundColor: COLORS,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// using this to change color of csv-button if dark mode is chosen
|
||||
var background = $('body').css("background-color");
|
||||
|
||||
if (background != ('rgb(255, 255, 255)')) {
|
||||
$(".buttons-csv").css("color", "white");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function totalBandQsos() {
|
||||
// using this to change color of legend and label according to background color
|
||||
var color = ifDarkModeThemeReturn('white', 'grey');
|
||||
|
||||
$.ajax({
|
||||
url: base_url+'index.php/statistics/get_band',
|
||||
type: 'post',
|
||||
success: function (data) {
|
||||
if (data.length > 0) {
|
||||
|
||||
$(".band").append('<br /><div style="display: flex;" id="bandContainer"><h2>Bands</h2><div style="flex: 1;"><canvas id="bandChart" width="500" height="500"></canvas></div><div style="flex: 1;" id="bandTable"></div></div><br />');
|
||||
|
||||
// appending table to hold the data
|
||||
$("#bandTable").append('<table style="width:100%" class="bandtable table table-sm table-bordered table-hover table-striped table-condensed text-center"><thead>' +
|
||||
'<tr>' +
|
||||
'<td>#</td>' +
|
||||
'<td>Band</td>' +
|
||||
'<td># of QSO\'s worked </td>' +
|
||||
'</tr>' +
|
||||
'</thead>' +
|
||||
'<tbody></tbody></table>');
|
||||
var labels = [];
|
||||
var dataQso = [];
|
||||
|
||||
var $myTable = $('.bandtable');
|
||||
var i = 1;
|
||||
|
||||
// building the rows in the table
|
||||
var rowElements = data.map(function (row) {
|
||||
|
||||
var $row = $('<tr></tr>');
|
||||
|
||||
var $iterator = $('<td></td>').html(i++);
|
||||
var $type = $('<td></td>').html(row.band);
|
||||
var $content = $('<td></td>').html(row.count);
|
||||
|
||||
$row.append($iterator, $type, $content);
|
||||
|
||||
return $row;
|
||||
});
|
||||
|
||||
// finally inserting the rows
|
||||
$myTable.append(rowElements);
|
||||
|
||||
$.each(data, function () {
|
||||
labels.push(this.band);
|
||||
dataQso.push(this.count);
|
||||
});
|
||||
|
||||
const COLORS = ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499"]
|
||||
var ctx = document.getElementById("bandChart").getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
plugins: [ChartPieChartOutlabels],
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Number of QSO\'s worked',
|
||||
data: dataQso,
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
backgroundColor: ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499"],
|
||||
borderWidth: 1,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
layout: {
|
||||
padding: 100
|
||||
},
|
||||
title: {
|
||||
fontColor: color,
|
||||
fullSize: true,
|
||||
},
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
labels: {
|
||||
boxWidth: 15,
|
||||
color: color,
|
||||
font: {
|
||||
size: 14,
|
||||
}
|
||||
},
|
||||
position: 'right',
|
||||
align: "middle"
|
||||
},
|
||||
outlabels: {
|
||||
backgroundColor: COLORS,
|
||||
borderColor: COLORS,
|
||||
borderRadius: 2, // Border radius of Label
|
||||
borderWidth: 2, // Thickness of border
|
||||
color: 'white',
|
||||
stretch: 45,
|
||||
padding: 0,
|
||||
font: {
|
||||
resizable: true,
|
||||
minSize: 15,
|
||||
maxSize: 25,
|
||||
family: Chart.defaults.font.family,
|
||||
size: Chart.defaults.font.size,
|
||||
style: Chart.defaults.font.style,
|
||||
lineHeight: Chart.defaults.font.lineHeight,
|
||||
},
|
||||
zoomOutPercentage: 100,
|
||||
textAlign: 'start',
|
||||
backgroundColor: COLORS,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.bandtable').DataTable({
|
||||
responsive: false,
|
||||
ordering: false,
|
||||
"scrollY": "170px",
|
||||
"scrollCollapse": true,
|
||||
"paging": false,
|
||||
"scrollX": true,
|
||||
bFilter: false,
|
||||
bInfo: false,
|
||||
});
|
||||
|
||||
// using this to change color of csv-button if dark mode is chosen
|
||||
var background = $('body').css("background-color");
|
||||
|
||||
if (background != ('rgb(255, 255, 255)')) {
|
||||
$(".buttons-csv").css("color", "white");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function totalSatQsos() {
|
||||
// using this to change color of legend and label according to background color
|
||||
var color = ifDarkModeThemeReturn('white', 'grey');
|
||||
|
||||
$.ajax({
|
||||
url: base_url+'index.php/statistics/get_sat',
|
||||
type: 'post',
|
||||
success: function (data) {
|
||||
if (data.length > 0) {
|
||||
$('.tabs').removeAttr('hidden');
|
||||
|
||||
var labels = [];
|
||||
var dataQso = [];
|
||||
|
||||
var $myTable = $('.sattable');
|
||||
var i = 1;
|
||||
|
||||
// building the rows in the table
|
||||
var rowElements = data.map(function (row) {
|
||||
|
||||
var $row = $('<tr></tr>');
|
||||
|
||||
var $iterator = $('<td></td>').html(i++);
|
||||
var $type = $('<td></td>').html(row.sat);
|
||||
var $content = $('<td></td>').html(row.count);
|
||||
|
||||
$row.append($iterator, $type, $content);
|
||||
|
||||
return $row;
|
||||
});
|
||||
|
||||
// finally inserting the rows
|
||||
$myTable.append(rowElements);
|
||||
|
||||
$.each(data, function () {
|
||||
labels.push(this.sat);
|
||||
dataQso.push(this.count);
|
||||
});
|
||||
|
||||
const COLORS = ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499"]
|
||||
var ctx = document.getElementById("satChart").getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
plugins: [ChartPieChartOutlabels],
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
label: 'Number of QSO\'s worked',
|
||||
data: dataQso,
|
||||
backgroundColor: ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00", "#b82e2e", "#316395", "#994499"],
|
||||
borderWidth: 1,
|
||||
labels: labels,
|
||||
}]
|
||||
},
|
||||
|
||||
options: {
|
||||
layout: {
|
||||
padding: 100
|
||||
},
|
||||
title: {
|
||||
fontColor: color,
|
||||
fullSize: true,
|
||||
},
|
||||
responsive: false,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
labels: {
|
||||
boxWidth: 15,
|
||||
color: color,
|
||||
font: {
|
||||
size: 14,
|
||||
}
|
||||
},
|
||||
position: 'right',
|
||||
align: "middle"
|
||||
},
|
||||
outlabels: {
|
||||
backgroundColor: COLORS,
|
||||
borderColor: COLORS,
|
||||
borderRadius: 2, // Border radius of Label
|
||||
borderWidth: 2, // Thickness of border
|
||||
color: 'white',
|
||||
stretch: 45,
|
||||
padding: 0,
|
||||
font: {
|
||||
resizable: true,
|
||||
minSize: 15,
|
||||
maxSize: 25,
|
||||
family: Chart.defaults.font.family,
|
||||
size: Chart.defaults.font.size,
|
||||
style: Chart.defaults.font.style,
|
||||
lineHeight: Chart.defaults.font.lineHeight,
|
||||
},
|
||||
zoomOutPercentage: 100,
|
||||
textAlign: 'start',
|
||||
backgroundColor: COLORS,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// using this to change color of csv-button if dark mode is chosen
|
||||
var background = $('body').css("background-color");
|
||||
|
||||
if (background != ('rgb(255, 255, 255)')) {
|
||||
$(".buttons-csv").css("color", "white");
|
||||
}
|
||||
|
||||
$('.sattable').DataTable({
|
||||
responsive: false,
|
||||
ordering: false,
|
||||
"scrollY": "170px",
|
||||
"scrollX": true,
|
||||
"ScrollCollapse": true,
|
||||
"paging": false,
|
||||
bFilter: false,
|
||||
bInfo: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
Ładowanie…
Reference in New Issue