added directives for chunkbar and graphs, with overall fixes in improvement in angular implementation
This commit is contained in:
parent
6481737c61
commit
73dbcb67e0
27
angular.html
27
angular.html
|
@ -32,6 +32,9 @@
|
|||
<!-- webui core -->
|
||||
<script src="js/app.js"></script>
|
||||
|
||||
<script src="js/directives/chunkbar.js"></script>
|
||||
<script src="js/directives/dgraph.js"></script>
|
||||
|
||||
<script src="js/services/deps.js"></script>
|
||||
<script src="js/services/base64.js"></script>
|
||||
<script src="js/services/utils.js"></script>
|
||||
|
@ -136,8 +139,10 @@
|
|||
</div>
|
||||
<!-- }}} -->
|
||||
|
||||
<!-- {{{ downloads -->
|
||||
<div role="main" class="container" ng-controller="DownloadCtrl">
|
||||
|
||||
<!-- {{{ download template -->
|
||||
<table ng-repeat="download in getDownloads()" class="download" data-gid="{{download.gid}}">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
@ -178,8 +183,10 @@
|
|||
<li ng-show="download.booleans.can_pause" class="label label-success hidden-phone">Downloaded: <span class="download-completedLength">{{download.completedLength}}</span></li>
|
||||
<li ng-show="download.booleans.can_pause" class="label label-success hidden-phone hidden-tablet">Progress: <span class="download-percentage">{{download.percentage}}</span>%</li>
|
||||
<li ng-show="download.booleans.can_pause" class="label label-success">Speed: <span class="download-downloadSpeed">{{download.downloadSpeed}}</span></li>
|
||||
<!-- TODO: figure out how to do multiple ng-show
|
||||
<li ng-show="download.booleans.bittorrent" class="label label-success hidden-phone">Upload Speed: <span class="download-uploadSpeed">{{download.uploadSpeed}}</span></li>
|
||||
-->
|
||||
|
||||
<li ng-show="download.booleans.bittorrent" class="label">Upload Speed: <span class="download-uploadSpeed">{{download.uploadSpeed}}</span></li>
|
||||
|
||||
<li ng-show="download.booleans.can_play" class="label label-info">Status: <span class="download-status">{{download.status}}</span></li>
|
||||
<li ng-show="download.booleans.can_play" class="label label-info">Size: <span class="download-totalLength">{{download.totalLength}}</span></li>
|
||||
|
@ -208,7 +215,7 @@
|
|||
<div class="bar" style="width: {{download.percentage}}%;"></div>
|
||||
</div>
|
||||
|
||||
<div ng-show="download.booleans.is_play" class="progress progress-info progress-striped" style="width: 100%; margin: 0; padding: 0;">
|
||||
<div ng-show="download.booleans.can_play" class="progress progress-info progress-striped" style="width: 100%; margin: 0; padding: 0;">
|
||||
<div class="bar" style="width: {{download.percentage}}%;"></div>
|
||||
</div>
|
||||
|
||||
|
@ -229,7 +236,7 @@
|
|||
<tr data-toggle="collapse" data-target="[data-gid={{download.gid}}] .download-detail .collapse" class="download-detail">
|
||||
<td colspan="2">
|
||||
<div class="collapse more_info">
|
||||
<canvas class="progress chunk-canvas" width="1400" style="width: 100%; margin: 5px;"></canvas>
|
||||
<canvas bitfield="download.bitfield" pieces="download.numPieces" class="progress chunk-canvas" width="1400" style="width: 100%; margin: 5px;" chunkbar></canvas>
|
||||
<ul class="stats">
|
||||
<li class="label">Status: <span class="download-status">{{download.status}}</span></li>
|
||||
<li class="label">GID: <span class="download-gid">{{download.gid}}</span></li>
|
||||
|
@ -249,19 +256,27 @@
|
|||
|
||||
<h4 class="hidden-phone">Download Files</h4>
|
||||
<ul class="download-files hidden-phone">
|
||||
<li class="label" ng-repeat="file in download.files">{{download.download.path}} ({{download.download.length}})</li>
|
||||
<li class="label" ng-repeat="file in download.files">{{file.path}} ({{file.length}})</li>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<div class="active_graph"></div>
|
||||
<div ng-show="download.booleans.can_pause">
|
||||
<div class="download-graph" dspeed="download.dspeed" uspeed="download.uspeed" dgraph></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- }}} -->
|
||||
|
||||
</div>
|
||||
<!-- }}} -->
|
||||
|
||||
<!-- {{{ modals -->
|
||||
<div ng-controller="ModalCtrl">
|
||||
|
||||
</div>
|
||||
<!-- }}} -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.active_graph {
|
||||
.download-graph {
|
||||
width: 80%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
|
|
@ -52,11 +52,6 @@
|
|||
text-align: center;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.active_graph {
|
||||
width: 80%;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.download_item {
|
||||
margin-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
|
@ -123,7 +118,7 @@
|
|||
<li class="label label-success hidden-phone hidden-tablet">Progress: <span class="download-percentage">{{percentage}}</span>%</li>
|
||||
<li class="label label-success">Speed: <span class="download-downloadSpeed">{{downloadSpeed}}</span></li>
|
||||
{{#booleans.bittorrent}}
|
||||
<li class="label">Upload Speed: <span class="download-uploadSpeed">{{uploadSpeed}}</span></li>
|
||||
<li class="label label-success hidden-phone">Upload Speed: <span class="download-uploadSpeed">{{uploadSpeed}}</span></li>
|
||||
{{/booleans.bittorrent}}
|
||||
{{/booleans.can_pause}}
|
||||
{{#booleans.can_play}}
|
||||
|
@ -209,7 +204,7 @@
|
|||
</ul>
|
||||
|
||||
<div>
|
||||
<div class="active_graph"></div>
|
||||
<div class="download-graph"></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
|
|
@ -14,20 +14,20 @@ function(scope, rpc, utils) {
|
|||
rpc.subscribe('tellActive', [], function(data) {
|
||||
console.log('got active data');
|
||||
scope.$apply(function() {
|
||||
scope.mapDownloads(data[0], scope.active);
|
||||
utils.mergeMap(data[0], scope.active, scope.getCtx);
|
||||
});
|
||||
});
|
||||
|
||||
rpc.subscribe('tellWaiting', [0, 100], function(data) {
|
||||
rpc.subscribe('tellWaiting', [0, 1000], function(data) {
|
||||
scope.$apply(function() {
|
||||
scope.mapDownloads(data[0], scope.waiting);
|
||||
utils.mergeMap(data[0], scope.waiting, scope.getCtx);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
rpc.subscribe('tellStopped', [0, 100], function(data) {
|
||||
rpc.subscribe('tellStopped', [0, 1000], function(data) {
|
||||
scope.$apply(function() {
|
||||
scope.mapDownloads(data[0], scope.stopped);
|
||||
utils.mergeMap(data[0], scope.stopped, scope.getCtx);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -37,33 +37,12 @@ function(scope, rpc, utils) {
|
|||
|
||||
return downs;
|
||||
}
|
||||
scope.mapDownloads = function(downs, mdowns) {
|
||||
if (!mdowns) mdowns = [];
|
||||
|
||||
for (i = 0; i < mdowns.length; i++) {
|
||||
if (i >= downs.length) {
|
||||
// remove the deleted downloads
|
||||
mdowns.splice(i, mdowns.length - downs.length);
|
||||
break;
|
||||
}
|
||||
if (!mdowns[i]) mdowns[i] = {};
|
||||
|
||||
scope.getCtx(downs[i], mdowns[i]);
|
||||
}
|
||||
|
||||
// insert newly created downloads
|
||||
while (i < downs.length) {
|
||||
mdowns.push(scope.getCtx(downs[i++]));
|
||||
}
|
||||
|
||||
return mdowns;
|
||||
}
|
||||
|
||||
|
||||
scope.getCtx = function(d, ctx) {
|
||||
ctx = ctx || {};
|
||||
|
||||
ctx.status = d.status;
|
||||
ctx.bitfield = d.bitfield;
|
||||
ctx.gid = d.gid;
|
||||
ctx.numPieces = d.numPieces;
|
||||
ctx.connections = d.connections;
|
||||
|
@ -86,8 +65,12 @@ function(scope, rpc, utils) {
|
|||
ctx[e] = utils.changeLength(d[e], 'B');
|
||||
});
|
||||
|
||||
// raw data for graphs
|
||||
ctx.dspeed = d.downloadSpeed;
|
||||
ctx.uspeed = d.uploadSpeed;
|
||||
|
||||
ctx.eta = utils.changeTime(
|
||||
(d.remainingLength) / d.downloadSpeed
|
||||
(d.totalLength-d.completedLength) / d.downloadSpeed
|
||||
);
|
||||
|
||||
var percentage = (d.completedLength / d.totalLength)*100;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
app.controller('ModalCtrl', ['$scope', function(scope) {
|
||||
|
||||
}]);
|
||||
|
|
37
js/directives/chunkbar.js
Normal file
37
js/directives/chunkbar.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
var draw = function(canvas, chunks, fillStyle) {
|
||||
chunks = chunks || [];
|
||||
if (!canvas.getContext) {
|
||||
console.log('use chunk bar on an canvas implementation!');
|
||||
return;
|
||||
}
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.fillStyle = fillStyle || "#149BDF";
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
var x = 0,
|
||||
width = canvas.width,
|
||||
height = canvas.height;
|
||||
chunks.forEach(function(c) {
|
||||
var dx = c.ratio * width;
|
||||
if (c.show)
|
||||
ctx.fillRect(x, 0, dx, height);
|
||||
x += dx;
|
||||
});
|
||||
};
|
||||
app.directive('chunkbar', ['$utils', function(utils) {
|
||||
return function(scope, elem, attrs) {
|
||||
var bitfield = "", pieces = 0;
|
||||
var update = function() {
|
||||
draw(elem[0], utils.getChunksFromHex(bitfield, pieces), attrs.fillStyle);
|
||||
};
|
||||
scope.$watch(attrs.bitfield, function(bf) {
|
||||
bitfield = bf;
|
||||
update();
|
||||
});
|
||||
scope.$watch(attrs.pieces, function(p) {
|
||||
pieces = p;
|
||||
update();
|
||||
});
|
||||
|
||||
update();
|
||||
};
|
||||
}]);
|
74
js/directives/dgraph.js
Normal file
74
js/directives/dgraph.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
|
||||
app.directive('dgraph', ['$', '$utils', function($, utils) {
|
||||
|
||||
return function(scope, elem, attrs) {
|
||||
|
||||
var graphSize = 20
|
||||
, dspeed = 0, uspeed = 0
|
||||
, dconf = {
|
||||
label: "Download Speed",
|
||||
data: [],
|
||||
color: "#ff0000",
|
||||
lines: { show: true }
|
||||
}
|
||||
, uconf = {
|
||||
label: "Upload Speed",
|
||||
data: [],
|
||||
color: "#00ff00",
|
||||
lines: { show: true }
|
||||
},
|
||||
start = new Date
|
||||
;
|
||||
|
||||
// jqplot doesnt draw graphs with no fixed height
|
||||
elem.height(elem.width() / 2);
|
||||
|
||||
var graph = $.plot(elem, [dconf, uconf], {
|
||||
legend: { show: true },
|
||||
xaxis: {
|
||||
show: true
|
||||
},
|
||||
yaxis: {
|
||||
tickFormatter: function(val, axis) {
|
||||
return utils.changeLength(val, "B/s");
|
||||
}
|
||||
,
|
||||
min: 0
|
||||
}
|
||||
});
|
||||
|
||||
var draw = function() {
|
||||
var height = elem.height();
|
||||
if (height <= 0) return;
|
||||
|
||||
elem.height(elem.width() / 2);
|
||||
|
||||
var cnt = ((new Date - start)/1000).toFixed(0);
|
||||
|
||||
dconf.data.push([cnt, dspeed]);
|
||||
if (dconf.data.length > graphSize) dconf.data.shift();
|
||||
|
||||
uconf.data.push([cnt, uspeed]);
|
||||
if (uconf.data.length > graphSize) uconf.data.shift();
|
||||
|
||||
graph.setData([dconf, uconf]);
|
||||
graph.resize();
|
||||
graph.setupGrid();
|
||||
graph.draw();
|
||||
};
|
||||
|
||||
scope.$watch(attrs.dspeed, function(val) {
|
||||
dspeed = val;
|
||||
});
|
||||
|
||||
scope.$watch(attrs.useed, function(val) {
|
||||
uspeed = val;
|
||||
});
|
||||
|
||||
var interval = setInterval(draw, 1000);
|
||||
|
||||
elem.bind('$destroy', function() {
|
||||
clearInterval(interval);
|
||||
});
|
||||
};
|
||||
}]);
|
|
@ -592,7 +592,7 @@ function updateGraphData(data) {
|
|||
this.add(this.upSpeed, val);
|
||||
return this;
|
||||
},
|
||||
plot: that.createGraph('[data-gid=' + gid + '] .active_graph'),
|
||||
plot: that.createGraph('[data-gid=' + gid + '] .download-graph'),
|
||||
start: new Date()
|
||||
}
|
||||
})().addDown(downSpeed).addUp(upSpeed));
|
||||
|
|
|
@ -13,11 +13,37 @@ app.factory('$utils', function() {
|
|||
return str.join("");
|
||||
},
|
||||
|
||||
// maps the array in place to the destination
|
||||
// arr, dest (optional): array
|
||||
// func: a merge mapping func, see ctrls/download.js
|
||||
mergeMap: function(arr, dest, func) {
|
||||
if (!dest) dest = [];
|
||||
|
||||
for (i = 0; i < dest.length; i++) {
|
||||
if (i >= arr.length) {
|
||||
// remove the deleted downloads
|
||||
dest.splice(i, dest.length - arr.length);
|
||||
break;
|
||||
}
|
||||
if (!dest[i]) dest[i] = {};
|
||||
|
||||
func(arr[i], dest[i]);
|
||||
}
|
||||
|
||||
// insert newly created downloads
|
||||
while (i < arr.length) {
|
||||
dest.push(func(arr[i++]));
|
||||
}
|
||||
|
||||
return dest;
|
||||
},
|
||||
|
||||
// change time units
|
||||
changeTime: function(time) {
|
||||
time = parseInt(time);
|
||||
time = parseFloat(time);
|
||||
if (isNaN(time) || !isFinite(time)) return " infinite";
|
||||
if (!time) return " infinite";
|
||||
if (time < 60) return time + " s";
|
||||
if (time < 60) return time.toFixed(2) + " s";
|
||||
else if (time < 60*60) return (time/60).toFixed(2) + " min";
|
||||
else if (time < 60*60*24) return (time/(60*60)).toFixed(2) + " hours";
|
||||
else return (time/(60*60*24)).toFixed(2) + " days!";
|
||||
|
@ -25,8 +51,8 @@ app.factory('$utils', function() {
|
|||
|
||||
// change length units
|
||||
changeLength: function(len, pref) {
|
||||
len = parseInt(len);
|
||||
if(len <= (1<<10)) return len + " " + pref;
|
||||
len = parseFloat(len);
|
||||
if(len <= (1<<10)) return len.toFixed(1) + " " + pref;
|
||||
else if(len <= (1<<20)) return (len/(1<<10)).toFixed(1) + " K" + pref;
|
||||
else if(len <= (1<<30)) return (len/(1<<20)).toFixed(1) + " M" + pref;
|
||||
else return (len/(1<<30)).toFixed(1) + " G" + pref;
|
||||
|
|
Loading…
Reference in New Issue
Block a user