support display block status

This commit is contained in:
MaysWind 2016-06-11 20:53:04 +08:00
parent e874477e94
commit feb79aca2c
8 changed files with 197 additions and 37 deletions

View file

@ -286,6 +286,8 @@
<script src="scripts/controllers/settings-ariang.js"></script>
<script src="scripts/controllers/settings-aria2.js"></script>
<script src="scripts/controllers/status.js"></script>
<script src="scripts/directives/pieceBar.js"></script>
<script src="scripts/directives/pieceMap.js"></script>
<script src="scripts/directives/chart.js"></script>
<script src="scripts/directives/placeholder.js"></script>
<script src="scripts/directives/setting.js"></script>

View file

@ -30,6 +30,7 @@
"Error Occurred": "发生错误",
"Removed": "已删除",
"Downloaded / Stopped": "已完成 / 已停止",
"Uncompleted": "未完成",
"Settings": "系统设置",
"AriaNg Settings": "AriaNg 设置",
"Aria2 Settings": "Aria2 设置",

View file

@ -34,6 +34,7 @@
'Error Occurred': 'Error Occurred',
'Removed': 'Removed',
'Downloaded / Stopped': 'Downloaded / Stopped',
'Uncompleted': 'Uncompleted',
'Settings': 'Settings',
'AriaNg Settings': 'AriaNg Settings',
'Aria2 Settings': 'Aria2 Settings',

View file

@ -0,0 +1,48 @@
(function () {
'use strict';
angular.module('ariaNg').directive('ngPieceBar', ['aria2TaskService', function (aria2TaskService) {
return {
restrict: 'E',
template: '<canvas class="piece-bar progress"></canvas>',
replace: true,
scope: {
bitField: '=',
pieceCount: '=',
color: '@'
},
link: function (scope, element) {
var redraw = function () {
var canvas = element[0];
var combinedPieces = aria2TaskService.getCombinedPieces(scope.bitField, scope.pieceCount);
var context = canvas.getContext('2d');
context.fillStyle = scope.color || '#000';
context.clearRect(0, 0, canvas.width, canvas.height);
var posX = 0;
var width = canvas.width;
var height = canvas.height;
for (var i = 0; i < combinedPieces.length; i++) {
var piece = combinedPieces[i];
var pieceWidth = piece.count / scope.pieceCount * width;
if (piece.isCompleted) {
context.fillRect(posX, 0, pieceWidth, height);
}
posX += pieceWidth;
}
};
scope.$watch('bitField', function () {
redraw();
});
scope.$watch('pieceNumber', function () {
redraw();
});
}
};
}]);
})();

View file

@ -0,0 +1,33 @@
(function () {
'use strict';
angular.module('ariaNg').directive('ngPieceMap', ['aria2TaskService', function (aria2TaskService) {
return {
restrict: 'E',
template: '<div class="piece-map"></div>',
replace: true,
scope: {
bitField: '=',
pieceCount: '='
},
link: function (scope, element) {
var redraw = function () {
var pieces = aria2TaskService.getPieceStatus(scope.bitField, scope.pieceCount);
element.empty();
for (var i = 0; i < pieces.length; i++) {
element.append('<div class="piece' + (pieces[i] ? ' piece-completed' : '') + '"></div>');
}
};
scope.$watch('bitField', function () {
redraw();
});
scope.$watch('pieceNumber', function () {
redraw();
});
}
};
}]);
})();

View file

@ -283,56 +283,78 @@
processDownloadTask(tasks[i]);
}
},
getPieceStatus: function (bitField, pieceCount) {
var pieces = [];
if (!bitField) {
return pieces;
}
var pieceIndex = 0;
for (var i = 0; i < bitField.length; i++) {
var bitSet = parseInt(bitField[i], 16);
for (var j = 1; j <= 4; j++) {
var bit = (1 << (4 - j));
var isCompleted = (bitSet & bit) == bit;
pieces.push(isCompleted ? 1 : 0);
pieceIndex++;
if (pieceIndex >= pieceCount) {
break;
}
}
}
return pieces;
},
getCombinedPieces: function (bitField, pieceCount) {
var pieces = this.getPieceStatus(bitField, pieceCount);
var combinedPieces = [];
for (var i = 0; i < pieces.length; i++) {
var isCompleted = (pieces[i] == 1);
if (combinedPieces.length > 0 && combinedPieces[combinedPieces.length - 1].isCompleted == isCompleted) {
combinedPieces[combinedPieces.length - 1].count++;
} else {
combinedPieces.push({
isCompleted: isCompleted,
count: 1
});
}
}
return combinedPieces;
},
estimateHealthPercentFromPeers: function (task, peers) {
if (peers.length < 1) {
return task.completePercent;
}
var bitfieldCompletedArr = new Array(task.bitfield.length);
var bitfieldPieceArr = new Array(task.bitfield.length);
var totalLength = task.bitfield.length * 0xf;
var healthBitCount = 0;
for (var i = 0; i < task.bitfield.length; i++) {
var num = parseInt(task.bitfield[i], 16);
bitfieldCompletedArr[i] = 0;
bitfieldPieceArr[i] = 0;
if (num == 0xf) {
bitfieldCompletedArr[i] = num;
} else {
bitfieldPieceArr[i] = num;
}
}
var pieces = this.getPieceStatus(task.bitfield, task.numPieces);
for (var i = 0; i < peers.length; i++) {
var peer = peers[i];
var bitfield = peer.bitfield;
var peerPieces = this.getPieceStatus(peer.bitfield, task.numPieces);
for (var j = 0; j < bitfield.length; j++) {
var num = parseInt(bitfield[j], 16);
if (num == 0xf) {
bitfieldCompletedArr[j] += num;
} else {
bitfieldPieceArr[j] = Math.max(bitfieldPieceArr[j], num);
}
for (var j = 0; j < peerPieces.length; j++) {
pieces[j] += peerPieces[j];
}
}
for (var i = 0; i < bitfieldCompletedArr.length; i++) {
bitfieldCompletedArr[i] += bitfieldPieceArr[i];
}
var competedPieceCount = 0;
while (true) {
var completed = true;
for (var i = 0; i < bitfieldCompletedArr.length; i++) {
var bitCount = Math.min(bitfieldCompletedArr[i], 0xf);
healthBitCount += bitCount;
bitfieldCompletedArr[i] -= bitCount;
if (bitCount < 0xf) {
for (var i = 0; i < pieces.length; i++) {
if (pieces[i] > 0) {
competedPieceCount++;
pieces[i]--;
} else {
completed = false;
}
}
@ -342,7 +364,7 @@
}
}
var healthPercent = healthBitCount / totalLength * 100;
var healthPercent = competedPieceCount / task.numPieces * 100;
if (healthPercent < task.completePercent) {
healthPercent = task.completePercent;

View file

@ -623,6 +623,46 @@ td {
overflow-x: hidden;
}
/* piece-bar / piece-map */
.piece-bar-wrapper {
height: 20px;
}
.piece-bar {
width: 100%;
}
.piece-map {
padding-left: 6px;
padding-right: 2px;
line-height: 11px;
}
.piece-legends {
text-align: center;
margin-top: 4px;
margin-bottom: 4px;
}
.piece-legend {
display: inline-block;
margin-right: 4px;
}
.piece-map .piece, .piece-legend .piece {
width: 10px;
height: 10px;
background-color: #eef2f4;
border: #dee2e5 solid 1px;
display: inline-block;
margin-right: 1px;
}
.piece-map .piece.piece-completed, .piece-legend .piece.piece-completed {
background-color: #b8dd69;
border-color: #b8dd69;
}
/* task-table */
.task-table {
margin-left: 15px;
@ -831,3 +871,4 @@ td {
}
}
/* miscellaneous */

View file

@ -130,7 +130,17 @@
</div>
</div>
<div class="tab-pane" ng-class="{'active': context.currentTab == 'blocks'}">
<div class="piece-legends">
<div class="piece-legend">
<div class="piece piece-completed"></div>
<span translate>Completed</span>
</div>
<div class="piece-legend">
<div class="piece"></div>
<span translate>Uncompleted</span>
</div>
</div>
<ng-piece-map bit-field="task.bitfield" piece-count="task.numPieces"></ng-piece-map>
</div>
<div class="tab-pane" ng-class="{'active': context.currentTab == 'filelist'}">
<div class="task-table task-table-firstrow-noborder">
@ -200,7 +210,9 @@
<span ng-bind="peer.ip + ':' + peer.port"></span>
</div>
<div class="col-sm-3">
<div class="piece-bar-wrapper">
<ng-piece-bar bit-field="peer.bitfield" piece-count="task.numPieces" color="#149BDF"></ng-piece-bar>
</div>
</div>
<div class="col-sm-2 col-xs-4">
<span ng-bind="(peer.completePercent | percent: 2) + '%'"></span>