<%@ Page Title="Speed and ETA" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" %>
<%@ Register Assembly="AjaxUploader" Namespace="AjaxUploader.Controls" TagPrefix="au" %> 
<asp:Content ID="TitleContent" ContentPlaceHolderID="TitleContent" runat="server">Speed and ETA - AjaxUploader v5.2 Demos</asp:Content>
<asp:Content ID="HeaderContent" ContentPlaceHolderID="HeaderTitle" runat="server">Speed and ETA</asp:Content> 
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> 
<div class="demo-card"> <div class="demo-card-header">Upload Speed and ETA</div> <div class="demo-card-body"> <p class="demo-description"> Show real-time upload speed (KB/s or MB/s) and estimated time remaining
 by calculating transfer rate from progress events.
 </p> <div class="demo-expect"><strong>What you should see:</strong> live transfer speed and estimated time remaining per file, derived from progress deltas. Throttle your connection to watch the estimate adapt.</div> <div id="speedUploader"></div> <div id="speedStats" style="margin-top:1rem; font-size:0.9rem; color:#374151; display:none;"> <span id="speedValue">Speed: --</span> &nbsp;|&nbsp;
 <span id="etaValue">ETA: --</span> </div> <div class="code-panel"> <pre><code>onTaskStart: function(task) {
 startTime = Date.now();
},
onTaskProgress: function(task, pct) {
 var elapsed = (Date.now() - startTime) / 1000;
 var loaded = task.fileSize * (pct / 100);
 var speed = loaded / elapsed;
 speedEl.textContent = formatBytes(speed);
 var remaining = (elapsed / pct) * (100 - pct);
 etaEl.textContent = formatTime(remaining);
}</code></pre> </div> </div>
</div> 
</asp:Content> 
<asp:Content ID="ScriptsContent" ContentPlaceHolderID="ScriptsContent" runat="server">
<script> (function () {
 var stats = document.getElementById('speedStats');
 var speedEl = document.getElementById('speedValue');
 var etaEl = document.getElementById('etaValue');
 var host = document.getElementById('speedUploader');
 var startTime, startBytes;

 function formatBytes(b) {
 return b >= 1048576 ? (b / 1048576).toFixed(1) + ' MB/s'
 : (b / 1024).toFixed(0) + ' KB/s';
 }
 function formatTime(s) {
 if (s < 60) return Math.ceil(s) + 's';
 return Math.floor(s / 60) + 'm ' + Math.ceil(s % 60) + 's';
 }

 if (!host || !window.AjaxUploader || typeof AjaxUploader.create !== 'function') return;
 AjaxUploader.create(host, {
 uploadUrl: '<%= ResolveUrl("~/ajaxupload.axd/upload") %>',
 multiple: true,
 autoUpload: true,
 onTaskStart: function (task) {
 if (stats) stats.style.display = 'block';
 startTime = Date.now();
 startBytes = 0;
 },
 onTaskProgress: function (task, pct) {
 var now = Date.now();
 var elapsed = (now - startTime) / 1000;
 var loaded = (task.fileSize || 0) * (pct / 100);
 if (elapsed > 0.5) {
 var speed = loaded / elapsed;
 if (speedEl) speedEl.textContent = 'Speed: ' + formatBytes(speed);
 if (pct > 0 && pct < 100) {
 var remaining = (elapsed / pct) * (100 - pct);
 if (etaEl) etaEl.textContent = 'ETA: ' + formatTime(remaining);
 }
 }
 },
 onTaskComplete: function () {
 if (etaEl) etaEl.textContent = 'ETA: Complete';
 }
 });
 })();
</script>
</asp:Content>
