support display block status
This commit is contained in:
parent
e874477e94
commit
feb79aca2c
|
@ -286,6 +286,8 @@
|
||||||
<script src="scripts/controllers/settings-ariang.js"></script>
|
<script src="scripts/controllers/settings-ariang.js"></script>
|
||||||
<script src="scripts/controllers/settings-aria2.js"></script>
|
<script src="scripts/controllers/settings-aria2.js"></script>
|
||||||
<script src="scripts/controllers/status.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/chart.js"></script>
|
||||||
<script src="scripts/directives/placeholder.js"></script>
|
<script src="scripts/directives/placeholder.js"></script>
|
||||||
<script src="scripts/directives/setting.js"></script>
|
<script src="scripts/directives/setting.js"></script>
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"Error Occurred": "发生错误",
|
"Error Occurred": "发生错误",
|
||||||
"Removed": "已删除",
|
"Removed": "已删除",
|
||||||
"Downloaded / Stopped": "已完成 / 已停止",
|
"Downloaded / Stopped": "已完成 / 已停止",
|
||||||
|
"Uncompleted": "未完成",
|
||||||
"Settings": "系统设置",
|
"Settings": "系统设置",
|
||||||
"AriaNg Settings": "AriaNg 设置",
|
"AriaNg Settings": "AriaNg 设置",
|
||||||
"Aria2 Settings": "Aria2 设置",
|
"Aria2 Settings": "Aria2 设置",
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
'Error Occurred': 'Error Occurred',
|
'Error Occurred': 'Error Occurred',
|
||||||
'Removed': 'Removed',
|
'Removed': 'Removed',
|
||||||
'Downloaded / Stopped': 'Downloaded / Stopped',
|
'Downloaded / Stopped': 'Downloaded / Stopped',
|
||||||
|
'Uncompleted': 'Uncompleted',
|
||||||
'Settings': 'Settings',
|
'Settings': 'Settings',
|
||||||
'AriaNg Settings': 'AriaNg Settings',
|
'AriaNg Settings': 'AriaNg Settings',
|
||||||
'Aria2 Settings': 'Aria2 Settings',
|
'Aria2 Settings': 'Aria2 Settings',
|
||||||
|
|
48
app/scripts/directives/pieceBar.js
Normal file
48
app/scripts/directives/pieceBar.js
Normal 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
})();
|
33
app/scripts/directives/pieceMap.js
Normal file
33
app/scripts/directives/pieceMap.js
Normal 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
})();
|
|
@ -283,56 +283,78 @@
|
||||||
processDownloadTask(tasks[i]);
|
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) {
|
estimateHealthPercentFromPeers: function (task, peers) {
|
||||||
if (peers.length < 1) {
|
if (peers.length < 1) {
|
||||||
return task.completePercent;
|
return task.completePercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bitfieldCompletedArr = new Array(task.bitfield.length);
|
var pieces = this.getPieceStatus(task.bitfield, task.numPieces);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < peers.length; i++) {
|
for (var i = 0; i < peers.length; i++) {
|
||||||
var peer = peers[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++) {
|
for (var j = 0; j < peerPieces.length; j++) {
|
||||||
var num = parseInt(bitfield[j], 16);
|
pieces[j] += peerPieces[j];
|
||||||
|
|
||||||
if (num == 0xf) {
|
|
||||||
bitfieldCompletedArr[j] += num;
|
|
||||||
} else {
|
|
||||||
bitfieldPieceArr[j] = Math.max(bitfieldPieceArr[j], num);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < bitfieldCompletedArr.length; i++) {
|
var competedPieceCount = 0;
|
||||||
bitfieldCompletedArr[i] += bitfieldPieceArr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var completed = true;
|
var completed = true;
|
||||||
|
|
||||||
for (var i = 0; i < bitfieldCompletedArr.length; i++) {
|
for (var i = 0; i < pieces.length; i++) {
|
||||||
var bitCount = Math.min(bitfieldCompletedArr[i], 0xf);
|
if (pieces[i] > 0) {
|
||||||
healthBitCount += bitCount;
|
competedPieceCount++;
|
||||||
bitfieldCompletedArr[i] -= bitCount;
|
pieces[i]--;
|
||||||
|
} else {
|
||||||
if (bitCount < 0xf) {
|
|
||||||
completed = false;
|
completed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,7 +364,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var healthPercent = healthBitCount / totalLength * 100;
|
var healthPercent = competedPieceCount / task.numPieces * 100;
|
||||||
|
|
||||||
if (healthPercent < task.completePercent) {
|
if (healthPercent < task.completePercent) {
|
||||||
healthPercent = task.completePercent;
|
healthPercent = task.completePercent;
|
||||||
|
|
|
@ -623,6 +623,46 @@ td {
|
||||||
overflow-x: hidden;
|
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 */
|
||||||
.task-table {
|
.task-table {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
|
@ -831,3 +871,4 @@ td {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* miscellaneous */
|
||||||
|
|
|
@ -130,7 +130,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" ng-class="{'active': context.currentTab == 'blocks'}">
|
<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>
|
||||||
<div class="tab-pane" ng-class="{'active': context.currentTab == 'filelist'}">
|
<div class="tab-pane" ng-class="{'active': context.currentTab == 'filelist'}">
|
||||||
<div class="task-table task-table-firstrow-noborder">
|
<div class="task-table task-table-firstrow-noborder">
|
||||||
|
@ -200,7 +210,9 @@
|
||||||
<span ng-bind="peer.ip + ':' + peer.port"></span>
|
<span ng-bind="peer.ip + ':' + peer.port"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<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>
|
||||||
<div class="col-sm-2 col-xs-4">
|
<div class="col-sm-2 col-xs-4">
|
||||||
<span ng-bind="(peer.completePercent | percent: 2) + '%'"></span>
|
<span ng-bind="(peer.completePercent | percent: 2) + '%'"></span>
|
||||||
|
|
Reference in a new issue