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 -->
|
<!-- webui core -->
|
||||||
<script src="js/app.js"></script>
|
<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/deps.js"></script>
|
||||||
<script src="js/services/base64.js"></script>
|
<script src="js/services/base64.js"></script>
|
||||||
<script src="js/services/utils.js"></script>
|
<script src="js/services/utils.js"></script>
|
||||||
|
@ -136,8 +139,10 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- }}} -->
|
<!-- }}} -->
|
||||||
|
|
||||||
|
<!-- {{{ downloads -->
|
||||||
<div role="main" class="container" ng-controller="DownloadCtrl">
|
<div role="main" class="container" ng-controller="DownloadCtrl">
|
||||||
|
|
||||||
|
<!-- {{{ download template -->
|
||||||
<table ng-repeat="download in getDownloads()" class="download" data-gid="{{download.gid}}">
|
<table ng-repeat="download in getDownloads()" class="download" data-gid="{{download.gid}}">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<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">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 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>
|
<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">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>
|
<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 class="bar" style="width: {{download.percentage}}%;"></div>
|
||||||
</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 class="bar" style="width: {{download.percentage}}%;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -229,7 +236,7 @@
|
||||||
<tr data-toggle="collapse" data-target="[data-gid={{download.gid}}] .download-detail .collapse" class="download-detail">
|
<tr data-toggle="collapse" data-target="[data-gid={{download.gid}}] .download-detail .collapse" class="download-detail">
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<div class="collapse more_info">
|
<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">
|
<ul class="stats">
|
||||||
<li class="label">Status: <span class="download-status">{{download.status}}</span></li>
|
<li class="label">Status: <span class="download-status">{{download.status}}</span></li>
|
||||||
<li class="label">GID: <span class="download-gid">{{download.gid}}</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>
|
<h4 class="hidden-phone">Download Files</h4>
|
||||||
<ul class="download-files hidden-phone">
|
<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>
|
</ul>
|
||||||
|
|
||||||
<div>
|
<div ng-show="download.booleans.can_pause">
|
||||||
<div class="active_graph"></div>
|
<div class="download-graph" dspeed="download.dspeed" uspeed="download.uspeed" dgraph></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<!-- }}} -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- }}} -->
|
||||||
|
|
||||||
|
<!-- {{{ modals -->
|
||||||
|
<div ng-controller="ModalCtrl">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- }}} -->
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05);
|
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-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,11 +52,6 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
.active_graph {
|
|
||||||
width: 80%;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.download_item {
|
.download_item {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding-top: 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 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>
|
<li class="label label-success">Speed: <span class="download-downloadSpeed">{{downloadSpeed}}</span></li>
|
||||||
{{#booleans.bittorrent}}
|
{{#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.bittorrent}}
|
||||||
{{/booleans.can_pause}}
|
{{/booleans.can_pause}}
|
||||||
{{#booleans.can_play}}
|
{{#booleans.can_play}}
|
||||||
|
@ -209,7 +204,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="active_graph"></div>
|
<div class="download-graph"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -14,20 +14,20 @@ function(scope, rpc, utils) {
|
||||||
rpc.subscribe('tellActive', [], function(data) {
|
rpc.subscribe('tellActive', [], function(data) {
|
||||||
console.log('got active data');
|
console.log('got active data');
|
||||||
scope.$apply(function() {
|
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.$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.$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;
|
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) {
|
scope.getCtx = function(d, ctx) {
|
||||||
ctx = ctx || {};
|
ctx = ctx || {};
|
||||||
|
|
||||||
ctx.status = d.status;
|
ctx.status = d.status;
|
||||||
|
ctx.bitfield = d.bitfield;
|
||||||
ctx.gid = d.gid;
|
ctx.gid = d.gid;
|
||||||
ctx.numPieces = d.numPieces;
|
ctx.numPieces = d.numPieces;
|
||||||
ctx.connections = d.connections;
|
ctx.connections = d.connections;
|
||||||
|
@ -86,8 +65,12 @@ function(scope, rpc, utils) {
|
||||||
ctx[e] = utils.changeLength(d[e], 'B');
|
ctx[e] = utils.changeLength(d[e], 'B');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// raw data for graphs
|
||||||
|
ctx.dspeed = d.downloadSpeed;
|
||||||
|
ctx.uspeed = d.uploadSpeed;
|
||||||
|
|
||||||
ctx.eta = utils.changeTime(
|
ctx.eta = utils.changeTime(
|
||||||
(d.remainingLength) / d.downloadSpeed
|
(d.totalLength-d.completedLength) / d.downloadSpeed
|
||||||
);
|
);
|
||||||
|
|
||||||
var percentage = (d.completedLength / d.totalLength)*100;
|
var percentage = (d.completedLength / d.totalLength)*100;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
app.controller('ModalCtrl', ['$scope', function(scope) {
|
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);
|
this.add(this.upSpeed, val);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
plot: that.createGraph('[data-gid=' + gid + '] .active_graph'),
|
plot: that.createGraph('[data-gid=' + gid + '] .download-graph'),
|
||||||
start: new Date()
|
start: new Date()
|
||||||
}
|
}
|
||||||
})().addDown(downSpeed).addUp(upSpeed));
|
})().addDown(downSpeed).addUp(upSpeed));
|
||||||
|
|
|
@ -13,11 +13,37 @@ app.factory('$utils', function() {
|
||||||
return str.join("");
|
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
|
// change time units
|
||||||
changeTime: function(time) {
|
changeTime: function(time) {
|
||||||
time = parseInt(time);
|
time = parseFloat(time);
|
||||||
|
if (isNaN(time) || !isFinite(time)) return " infinite";
|
||||||
if (!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) return (time/60).toFixed(2) + " min";
|
||||||
else if (time < 60*60*24) return (time/(60*60)).toFixed(2) + " hours";
|
else if (time < 60*60*24) return (time/(60*60)).toFixed(2) + " hours";
|
||||||
else return (time/(60*60*24)).toFixed(2) + " days!";
|
else return (time/(60*60*24)).toFixed(2) + " days!";
|
||||||
|
@ -25,8 +51,8 @@ app.factory('$utils', function() {
|
||||||
|
|
||||||
// change length units
|
// change length units
|
||||||
changeLength: function(len, pref) {
|
changeLength: function(len, pref) {
|
||||||
len = parseInt(len);
|
len = parseFloat(len);
|
||||||
if(len <= (1<<10)) return len + " " + pref;
|
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<<20)) return (len/(1<<10)).toFixed(1) + " K" + pref;
|
||||||
else if(len <= (1<<30)) return (len/(1<<20)).toFixed(1) + " M" + pref;
|
else if(len <= (1<<30)) return (len/(1<<20)).toFixed(1) + " M" + pref;
|
||||||
else return (len/(1<<30)).toFixed(1) + " G" + pref;
|
else return (len/(1<<30)).toFixed(1) + " G" + pref;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user