Merge branch 'cc-4661-listener-statistics' of dev.sourcefabric.org:airtime into cc-4661-listener-statistics
This commit is contained in:
commit
034ea49d01
5 changed files with 176 additions and 71 deletions
|
@ -87,7 +87,7 @@ $pages = array(
|
||||||
'resource' => 'playouthistory'
|
'resource' => 'playouthistory'
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'label' => 'Listener Stat',
|
'label' => 'Listener Stats',
|
||||||
'module' => 'default',
|
'module' => 'default',
|
||||||
'controller' => 'listenerstat',
|
'controller' => 'listenerstat',
|
||||||
'action' => 'index',
|
'action' => 'index',
|
||||||
|
|
|
@ -18,6 +18,7 @@ class ListenerstatController extends Zend_Controller_Action
|
||||||
$baseUrl = $request->getBaseUrl();
|
$baseUrl = $request->getBaseUrl();
|
||||||
|
|
||||||
$this->view->headScript()->appendFile($baseUrl.'/js/flot/jquery.flot.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'/js/flot/jquery.flot.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
|
$this->view->headScript()->appendFile($baseUrl.'/js/flot/jquery.flot.crosshair.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/listenerstat/listenerstat.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/listenerstat/listenerstat.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
|
||||||
|
|
||||||
$offset = date("Z") * -1;
|
$offset = date("Z") * -1;
|
||||||
|
@ -46,9 +47,6 @@ class ListenerstatController extends Zend_Controller_Action
|
||||||
'his_time_end' => $end->format("H:i")
|
'his_time_end' => $end->format("H:i")
|
||||||
));
|
));
|
||||||
|
|
||||||
$allMPs = Application_Model_ListenerStat::getAllMPNames();
|
|
||||||
|
|
||||||
$this->view->mps = $allMPs;
|
|
||||||
$this->view->date_form = $form;
|
$this->view->date_form = $form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,33 +7,44 @@ class Application_Model_ListenerStat
|
||||||
|
|
||||||
public static function getDataPointsWithinRange($p_start, $p_end) {
|
public static function getDataPointsWithinRange($p_start, $p_end) {
|
||||||
$sql = <<<SQL
|
$sql = <<<SQL
|
||||||
SELECT lc.id, ts.timestamp, lc.listener_count, mn.mount_name
|
SELECT mount_name, count(*)
|
||||||
FROM cc_listener_count AS lc
|
FROM cc_listener_count AS lc
|
||||||
INNER JOIN cc_timestamp AS ts ON (lc.timestamp_id = ts.ID)
|
INNER JOIN cc_timestamp AS ts ON (lc.timestamp_id = ts.ID)
|
||||||
INNER JOIN cc_mount_name AS mn ON (lc.mount_name_id = mn.ID)
|
INNER JOIN cc_mount_name AS mn ON (lc.mount_name_id = mn.ID)
|
||||||
WHERE (ts.timestamp >=:p1 AND ts.timestamp <= :p2)
|
WHERE (ts.timestamp >=:p1 AND ts.timestamp <=:p2)
|
||||||
ORDER BY mount_name, timestamp
|
group by mount_name
|
||||||
SQL;
|
SQL;
|
||||||
$data = Application_Common_Database::prepareAndExecute($sql,
|
$data = Application_Common_Database::prepareAndExecute($sql,
|
||||||
array('p1'=>$p_start, 'p2'=>$p_end));
|
array('p1'=>$p_start, 'p2'=>$p_end));
|
||||||
|
|
||||||
$out = array();
|
$out = array();
|
||||||
foreach ($data as $d) {
|
foreach ($data as $d) {
|
||||||
$out[$d['mount_name']][] = $d;
|
$jump = intval($d['count']/1000);
|
||||||
}
|
$jump = max(1, $jump);
|
||||||
|
$remainder = $jump == 1?0:1;
|
||||||
|
|
||||||
return $out;
|
$sql = <<<SQL
|
||||||
}
|
SELECT *
|
||||||
|
FROM
|
||||||
public static function getAllMPNames() {
|
(SELECT lc.id, ts.timestamp, lc.listener_count, mn.mount_name,
|
||||||
$sql = <<<SQL
|
ROW_NUMBER() OVER (ORDER BY timestamp) as rownum
|
||||||
SELECT DISTINCT mount_name
|
FROM cc_listener_count AS lc
|
||||||
FROM cc_listener_count
|
INNER JOIN cc_timestamp AS ts ON (lc.timestamp_id = ts.ID)
|
||||||
|
INNER JOIN cc_mount_name AS mn ON (lc.mount_name_id = mn.ID)
|
||||||
|
WHERE (ts.timestamp >=:p1 AND ts.timestamp <= :p2) AND mount_name=:p3) as temp
|
||||||
|
WHERE (temp.rownum%:p4) = :p5;
|
||||||
SQL;
|
SQL;
|
||||||
$mps = Application_Common_Database::prepareAndExecute($sql, array());
|
$result = Application_Common_Database::prepareAndExecute($sql,
|
||||||
$out = array();
|
array('p1'=>$p_start, 'p2'=>$p_end, 'p3'=>$d['mount_name'], 'p4'=>$jump, 'p5'=>$remainder));
|
||||||
foreach ($mps as $mp) {
|
foreach ($result as $r) {
|
||||||
$out[] = $mp['mount_name'];
|
$t = new DateTime($r['timestamp'], new DateTimeZone("UTC"));
|
||||||
|
$t->setTimezone(new DateTimeZone(date_default_timezone_get()));
|
||||||
|
// tricking javascript so it thinks the server timezone is in UTC
|
||||||
|
$dt = new DateTime($t->format("Y-m-d H:i:s"), new DateTimeZone("UTC"));
|
||||||
|
|
||||||
|
$r['timestamp'] = $dt->format("U");
|
||||||
|
$out[$r['mount_name']][] = $r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
<div id="listenerstat_content" class="ui-widget ui-widget-content block-shadow alpha-block padded">
|
<div id="listenerstat_content" class="ui-widget ui-widget-content block-shadow alpha-block padded">
|
||||||
Timestamp vs Listener Count<br>
|
Listener Count Over Time<br>
|
||||||
<select id='all_mps'>
|
|
||||||
<option value="all">All Mount Potins</option>
|
|
||||||
<?php foreach($this->mps as $mp) {?>
|
|
||||||
<option value="<?php echo $mp?>"><?php echo $mp?></option>
|
|
||||||
<?php } ?>
|
|
||||||
</select>
|
|
||||||
<div id="flot_placeholder" style="width:600px;height:300px;margin:0px 50px 0px 50px"></div>
|
<div id="flot_placeholder" style="width:600px;height:300px;margin:0px 50px 0px 50px"></div>
|
||||||
|
<div id="legend" style="width:600px;height:70px;margin:0px 50px 0px 50px"></div>
|
||||||
<?php echo $this->date_form; ?>
|
<?php echo $this->date_form; ?>
|
||||||
|
|
||||||
</div>
|
</div>
|
|
@ -12,43 +12,148 @@ $(document).ready(function() {
|
||||||
endTimestamp = AIRTIME.utilities.fnGetTimestamp(dateEndId, timeEndId);
|
endTimestamp = AIRTIME.utilities.fnGetTimestamp(dateEndId, timeEndId);
|
||||||
getDataAndPlot(startTimestamp, endTimestamp);
|
getDataAndPlot(startTimestamp, endTimestamp);
|
||||||
});
|
});
|
||||||
|
|
||||||
listenerstat_content.find("#all_mps").change(function(){
|
|
||||||
var mpName = $(this).val();
|
|
||||||
startTimestamp = AIRTIME.utilities.fnGetTimestamp(dateStartId, timeStartId);
|
|
||||||
endTimestamp = AIRTIME.utilities.fnGetTimestamp(dateEndId, timeEndId);
|
|
||||||
getDataAndPlot(startTimestamp, endTimestamp);
|
|
||||||
getDataAndPlot(startTimestamp, endTimestamp, mpName);
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function getDataAndPlot(startTimestamp, endTimestamp, mountName){
|
function getDataAndPlot(startTimestamp, endTimestamp){
|
||||||
// get data
|
// get data
|
||||||
$.get('/Listenerstat/get-data', {startTimestamp: startTimestamp, endTimestamp: endTimestamp}, function(data){
|
$.get('/Listenerstat/get-data', {startTimestamp: startTimestamp, endTimestamp: endTimestamp}, function(data){
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
out = new Array();
|
out = new Object();
|
||||||
$.each(data, function(mpName, v){
|
$.each(data, function(mpName, v){
|
||||||
plotData = new Array();
|
plotData = new Object();
|
||||||
if (mountName != null && mpName != mountName){
|
plotData.data = new Array();
|
||||||
console.log(mountName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$.each(v, function(i, ele){
|
$.each(v, function(i, ele){
|
||||||
temp = new Array();
|
plotData.label = mpName;
|
||||||
temp[0] = new Date(ele.timestamp.replace(/-/g,"/"));
|
var d = new Date(0);
|
||||||
temp[1] = ele.listener_count;
|
d.setUTCSeconds(ele.timestamp);
|
||||||
plotData.push(temp);
|
plotData.data.push([d, ele.listener_count]);
|
||||||
})
|
})
|
||||||
out.push(plotData);
|
out[mpName] = plotData;
|
||||||
});
|
});
|
||||||
if (out.length == 0) {
|
|
||||||
out.push(new Array());
|
|
||||||
}
|
|
||||||
plot(out);
|
plot(out);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function plot(d){
|
function plot(datasets){
|
||||||
|
var plot;
|
||||||
|
data = null;
|
||||||
|
function plotByChoice(doAll)
|
||||||
|
{
|
||||||
|
// largest date object that you can set
|
||||||
|
firstTimestamp = new Date(8640000000000000);
|
||||||
|
// smallest
|
||||||
|
lastTimestamp = new Date(0);
|
||||||
|
|
||||||
|
data = [];
|
||||||
|
if (doAll != null)
|
||||||
|
{
|
||||||
|
$.each(datasets, function(key, val) {
|
||||||
|
if (firstTimestamp.getTime() > val.data[0][0].getTime()) {
|
||||||
|
firstTimestamp = val.data[0][0];
|
||||||
|
}
|
||||||
|
if (lastTimestamp.getTime() < val.data[val.data.length-1][0].getTime()) {
|
||||||
|
lastTimestamp = val.data[val.data.length-1][0];
|
||||||
|
}
|
||||||
|
data.push(val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#legend .legendCB').each(
|
||||||
|
function(){
|
||||||
|
if (this.checked)
|
||||||
|
{
|
||||||
|
data.push(datasets[this.id]);
|
||||||
|
if (firstTimestamp.getTime() > datasets[this.id].data[0][0].getTime()) {
|
||||||
|
firstTimestamp = datasets[this.id].data[0][0];
|
||||||
|
}
|
||||||
|
if (lastTimestamp.getTime() < datasets[this.id].data[datasets[this.id].data.length-1][0].getTime()) {
|
||||||
|
lastTimestamp = datasets[this.id].data[datasets[this.id].data.length-1][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.push({label: this.id, data: []})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfTicks = 10;
|
||||||
|
tickSize = (lastTimestamp.getTime() - firstTimestamp.getTime())/1000/numOfTicks;
|
||||||
|
|
||||||
|
plot = $.plot($("#flot_placeholder"), data, {
|
||||||
|
yaxis: { min: 0, tickDecimals: 0 },
|
||||||
|
xaxis: { mode: "time", timeformat:"%y/%m/%0d %H:%M", tickSize: [tickSize, "second"] },
|
||||||
|
grid: {
|
||||||
|
hoverable: true,
|
||||||
|
backgroundColor: { colors: ["#888888", "#999999"] }
|
||||||
|
},
|
||||||
|
series: {
|
||||||
|
lines: {
|
||||||
|
show: true,
|
||||||
|
fill: 0.3
|
||||||
|
},
|
||||||
|
points: { show: true }
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
container: $('#legend'),
|
||||||
|
noColumns: 5,
|
||||||
|
labelFormatter: function (label, series) {
|
||||||
|
var cb = '<input style="float:left;" class="legendCB" type="checkbox" ';
|
||||||
|
if (series.data.length > 0){
|
||||||
|
cb += 'checked="true" ';
|
||||||
|
}
|
||||||
|
cb += 'id="'+label+'" /> ';
|
||||||
|
cb += label;
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function showTooltip(x, y, contents) {
|
||||||
|
$('<div id="tooltip">' + contents + '</div>').css( {
|
||||||
|
position: 'absolute',
|
||||||
|
display: 'none',
|
||||||
|
top: y + 5,
|
||||||
|
left: x + 5,
|
||||||
|
border: '1px solid #fdd',
|
||||||
|
padding: '2px',
|
||||||
|
'background-color': '#fee',
|
||||||
|
opacity: 0.80
|
||||||
|
}).appendTo("body").fadeIn(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
var previousPoint = null;
|
||||||
|
$("#flot_placeholder").bind("plothover", function (event, pos, item) {
|
||||||
|
if (item) {
|
||||||
|
if (previousPoint != item.dataIndex) {
|
||||||
|
previousPoint = item.dataIndex;
|
||||||
|
|
||||||
|
$("#tooltip").remove();
|
||||||
|
var y = item.datapoint[1].toFixed(2);
|
||||||
|
|
||||||
|
showTooltip(item.pageX, item.pageY,
|
||||||
|
"Listener Count on '"+item.series.label + "': " + Math.floor(y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#tooltip").remove();
|
||||||
|
previousPoint = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#placeholder").bind("plotclick", function (event, pos, item) {
|
||||||
|
if (item) {
|
||||||
|
$("#clickdata").text("You clicked point " + item.dataIndex + " in " + item.series.label + ".");
|
||||||
|
plot.highlight(item.series, item.datapoint);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#legend').find("input").click(function(){setTimeout(plotByChoice,100);});
|
||||||
|
}
|
||||||
|
|
||||||
|
plotByChoice(true);
|
||||||
oBaseDatePickerSettings = {
|
oBaseDatePickerSettings = {
|
||||||
dateFormat: 'yy-mm-dd',
|
dateFormat: 'yy-mm-dd',
|
||||||
onSelect: function(sDate, oDatePicker) {
|
onSelect: function(sDate, oDatePicker) {
|
||||||
|
@ -67,7 +172,4 @@ function plot(d){
|
||||||
listenerstat_content.find(timeStartId).timepicker(oBaseTimePickerSettings);
|
listenerstat_content.find(timeStartId).timepicker(oBaseTimePickerSettings);
|
||||||
listenerstat_content.find(dateEndId).datepicker(oBaseDatePickerSettings);
|
listenerstat_content.find(dateEndId).datepicker(oBaseDatePickerSettings);
|
||||||
listenerstat_content.find(timeEndId).timepicker(oBaseTimePickerSettings);
|
listenerstat_content.find(timeEndId).timepicker(oBaseTimePickerSettings);
|
||||||
|
}
|
||||||
$.plot($("#flot_placeholder"), d, { xaxis: { mode: "time", timeformat: "%y/%m/%0d %H:%M:%S" } });
|
|
||||||
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue