/* eslint no-var: 0, camelcase: 0 */ var eventLeftMargin = 180; var eventRightMargin = 0; function canvasLoadEventUpdate(canvas, minTime, maxTime, events) { var event; var start; var ctx = canvas.getContext('2d'); for (var i = 0, y_offset = 20; i < events.length; i++) { event = events[i]; start = event.time; // var end = event.time + event.duration + event.latency; if (start >= minTime && start <= maxTime) { y_offset += 20; } } canvas.height = y_offset; ctx.fillStyle = 'green'; ctx.globalAlpha = 0.5; ctx.fillRect(0, 0, eventLeftMargin, canvas.height); ctx.fillRect( canvas.width - eventRightMargin, 0, eventRightMargin, canvas.height ); ctx.globalAlpha = 1; // draw legend var x_offset = 5; ctx.font = '12px Arial'; var legend = 'load event'; ctx.fillStyle = 'black'; ctx.fillText(legend, x_offset, 15); x_offset = eventLeftMargin + 5; legend = 'start - end'; ctx.fillStyle = 'black'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; legend = '[latency'; ctx.fillStyle = 'orange'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; legend = 'loading'; ctx.fillStyle = 'green'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; legend = 'parsing'; ctx.fillStyle = 'blue'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; legend = 'appending]'; ctx.fillStyle = 'red'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; legend = 'size bitrate'; ctx.fillStyle = 'black'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; for (i = 0, y_offset = 20; i < events.length; i++) { event = events[i]; start = Math.round(event.time); // var end = Math.round(event.time + event.duration + event.latency); if (start >= minTime && start <= maxTime) { canvasDrawLoadEvent(ctx, y_offset, event, minTime, maxTime); y_offset += 20; } } } function canvasVideoEventUpdate(canvas, minTime, maxTime, events) { var event; var start; var ctx = canvas.getContext('2d'); for (var i = 0, y_offset = 20; i < events.length; i++) { event = events[i]; start = event.time; // end = event.time; if (start >= minTime && start <= maxTime) { y_offset += 20; } } canvas.height = y_offset; ctx.fillStyle = 'green'; ctx.globalAlpha = 0.5; ctx.fillRect(0, 0, eventLeftMargin, canvas.height); ctx.fillRect( canvas.width - eventRightMargin, 0, eventRightMargin, canvas.height ); ctx.globalAlpha = 1; // draw legend var x_offset = 5; ctx.font = '12px Arial'; var legend = 'video event'; ctx.fillStyle = 'black'; ctx.fillText(legend, x_offset, 15); x_offset = eventLeftMargin + 5; legend = 'time'; ctx.fillStyle = 'black'; ctx.fillText(legend, x_offset, 15); x_offset += ctx.measureText(legend).width + 5; legend = '[duration]'; ctx.fillStyle = 'blue'; ctx.fillText(legend, x_offset, 15); for (i = 0, y_offset = 20; i < events.length; i++) { event = events[i]; start = Math.round(event.time); // end = Math.round(event.time); if (start >= minTime && start <= maxTime) { canvasDrawVideoEvent(ctx, y_offset, event, minTime, maxTime); y_offset += 20; } } } function canvasBufferWindowUpdate(canvas, minTime, maxTime, focusTime, events) { var ctx = canvas.getContext('2d'); var minTimeBuffer; var minTimePos; var focusTimeBuffer; var focusTimePos; var bufferChartStart = eventLeftMargin; var bufferChartWidth = ctx.canvas.width - eventLeftMargin - eventRightMargin; ctx.clearRect(0, 0, canvas.width, canvas.height); if (events.length === 0) { return; } ctx.fillStyle = 'green'; ctx.globalAlpha = 0.5; ctx.fillRect(0, 0, eventLeftMargin, canvas.height); ctx.globalAlpha = 1; // draw legend var x_offset = 5; var y_offset = 0; ctx.font = '15px Arial'; var maxBuffer = 0; var firstEventIdx = -1; var focusEventIdx = -1; var event; for (var i = 0; i < events.length; i++) { event = events[i]; maxBuffer = Math.max(maxBuffer, event.buffer + event.pos); if (firstEventIdx === -1 && event.time >= minTime) { firstEventIdx = Math.max(0, i - 1); } if (focusEventIdx === -1 && event.time >= focusTime) { focusEventIdx = Math.max(0, i - 1); } } // compute position and buffer length at pos minTime using linear approximation if (firstEventIdx + 1 < events.length) { minTimePos = events[firstEventIdx].pos + ((minTime - events[firstEventIdx].time) * (events[firstEventIdx + 1].pos - events[firstEventIdx].pos)) / (events[firstEventIdx + 1].time - events[firstEventIdx].time); minTimeBuffer = minTimePos + events[firstEventIdx].buffer + ((minTime - events[firstEventIdx].time) * (events[firstEventIdx + 1].buffer - events[firstEventIdx].buffer)) / (events[firstEventIdx + 1].time - events[firstEventIdx].time); } else { minTimeBuffer = 0; minTimePos = 0; } // compute position and buffer length at pos focusTime using linear approximation if (focusEventIdx + 1 < events.length) { focusTimePos = events[focusEventIdx].pos + ((focusTime - events[focusEventIdx].time) * (events[focusEventIdx + 1].pos - events[focusEventIdx].pos)) / (events[focusEventIdx + 1].time - events[focusEventIdx].time); focusTimeBuffer = events[focusEventIdx].buffer + ((focusTime - events[focusEventIdx].time) * (events[focusEventIdx + 1].buffer - events[focusEventIdx].buffer)) / (events[focusEventIdx + 1].time - events[focusEventIdx].time); } else { focusTimePos = 0; focusTimeBuffer = 0; } maxBuffer *= 1.1; y_offset += 15; var legend = 'play pos/buffer zoomed'; ctx.fillStyle = 'black'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = '[' + minTime + ',' + maxTime + ']'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'focus time:' + focusTime + ' ms'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'focus position:' + Math.round(focusTimePos) + ' ms'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'focus buffer:' + Math.round(focusTimeBuffer) + ' ms'; ctx.fillText(legend, x_offset, y_offset); ctx.fillStyle = 'blue'; ctx.beginPath(); ctx.moveTo(bufferChartStart, ctx.canvas.height); ctx.lineTo( bufferChartStart, ctx.canvas.height * (1 - minTimeBuffer / maxBuffer) ); for (var j = firstEventIdx + 1; j < events.length; j++) { event = events[j]; x_offset = bufferChartStart + (bufferChartWidth * (event.time - minTime)) / (maxTime - minTime); y_offset = ctx.canvas.height * (1 - (event.buffer + event.pos) / maxBuffer); ctx.lineTo(x_offset, y_offset); } ctx.lineTo(x_offset, canvas.height); ctx.fill(); ctx.fillStyle = 'brown'; ctx.beginPath(); ctx.moveTo(bufferChartStart, ctx.canvas.height); ctx.lineTo( bufferChartStart, ctx.canvas.height * (1 - minTimePos / maxBuffer) ); for (var k = firstEventIdx + 1; k < events.length; k++) { event = events[k]; x_offset = bufferChartStart + (bufferChartWidth * (event.time - minTime)) / (maxTime - minTime); y_offset = ctx.canvas.height * (1 - event.pos / maxBuffer); ctx.lineTo(x_offset, y_offset); } ctx.lineTo(x_offset, canvas.height); ctx.fill(); ctx.fillStyle = 'white'; ctx.fillRect( canvas.width - eventRightMargin, 0, eventRightMargin, canvas.height ); ctx.fillStyle = 'green'; ctx.globalAlpha = 0.5; ctx.fillRect( canvas.width - eventRightMargin, 0, eventRightMargin, canvas.height ); ctx.globalAlpha = 1; ctx.fillStyle = 'black'; x_offset = bufferChartStart + (bufferChartWidth * (focusTime - minTime)) / (maxTime - minTime); ctx.moveTo(x_offset, ctx.canvas.height); y_offset = ctx.canvas.height * (1 - (focusTimePos + focusTimeBuffer) / maxBuffer); ctx.lineTo(x_offset, y_offset); ctx.stroke(); } function canvasBufferTimeRangeUpdate( canvas, minTime, maxTime, windowMinTime, windowMaxTime, events ) { var ctx = canvas.getContext('2d'); var bufferChartStart = eventLeftMargin; var bufferChartWidth = ctx.canvas.width - eventLeftMargin - eventRightMargin; var x_offset = 0; var y_offset = 0; var event; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = 'green'; ctx.globalAlpha = 0.5; ctx.fillRect(0, 0, eventLeftMargin, canvas.height); ctx.fillRect( canvas.width - eventRightMargin, 0, eventRightMargin, canvas.height ); ctx.globalAlpha = 1; x_offset = 5; y_offset = 15; var legend = 'play pos/buffer'; ctx.fillStyle = 'black'; ctx.font = '15px Arial'; ctx.fillText(legend, x_offset, y_offset); if (events.length === 0) { return; } var maxBuffer = 0; for (var i = 0; i < events.length; i++) { maxBuffer = Math.max(maxBuffer, events[i].buffer + events[i].pos); } y_offset += 15; legend = 'last pos:' + events[events.length - 1].pos + ' ms'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'last buffer:' + events[events.length - 1].buffer + ' ms'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'max buffer:' + maxBuffer + ' ms'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'nb samples:' + events.length; ctx.fillText(legend, x_offset, y_offset); maxBuffer *= 1.1; ctx.fillStyle = 'blue'; ctx.beginPath(); ctx.moveTo(bufferChartStart, ctx.canvas.height); for (var j = 0; j < events.length; j++) { event = events[j]; x_offset = bufferChartStart + (bufferChartWidth * (event.time - minTime)) / (maxTime - minTime); y_offset = ctx.canvas.height * (1 - (event.buffer + event.pos) / maxBuffer); ctx.lineTo(x_offset, y_offset); } ctx.lineTo(x_offset, canvas.height); ctx.fill(); ctx.fillStyle = 'brown'; ctx.beginPath(); ctx.moveTo(bufferChartStart, ctx.canvas.height); for (var k = 0; k < events.length; k++) { event = events[k]; x_offset = bufferChartStart + (bufferChartWidth * (event.time - minTime)) / (maxTime - minTime); y_offset = ctx.canvas.height * (1 - event.pos / maxBuffer); ctx.lineTo(x_offset, y_offset); } ctx.lineTo(x_offset, canvas.height); ctx.fill(); ctx.globalAlpha = 0.7; ctx.fillStyle = 'grey'; var x_start = bufferChartStart; var x_w = (bufferChartWidth * (windowMinTime - minTime)) / (maxTime - minTime); ctx.fillRect(x_start, 0, x_w, canvas.height); x_start = bufferChartStart + (bufferChartWidth * (windowMaxTime - minTime)) / (maxTime - minTime); x_w = canvas.width - x_start - eventRightMargin; ctx.fillRect(x_start, 0, x_w, canvas.height); ctx.globalAlpha = 1; } function canvasBitrateEventUpdate( canvas, minTime, maxTime, windowMinTime, windowMaxTime, levelEvents, bitrateEvents ) { var ctx = canvas.getContext('2d'); var bufferChartStart = eventLeftMargin; var bufferChartWidth = ctx.canvas.width - eventLeftMargin - eventRightMargin; var x_offset = 0; var y_offset = 0; var event; var maxLevel; var minLevel; var sumLevel; var maxBitrate; var minBitrate; var sumDuration; ctx.clearRect(0, 0, canvas.width, canvas.height); if (levelEvents.length === 0 || bitrateEvents.length === 0) { return; } maxBitrate = minBitrate = bitrateEvents[0].bitrate; sumLevel = sumDuration = 0; for (var i = 0; i < bitrateEvents.length; i++) { sumLevel += bitrateEvents[i].duration * bitrateEvents[i].level; sumDuration += bitrateEvents[i].duration; maxBitrate = Math.max(maxBitrate, bitrateEvents[i].bitrate); minBitrate = Math.min(minBitrate, bitrateEvents[i].bitrate); } maxLevel = minLevel = levelEvents[0].id; for (var j = 0; j < levelEvents.length; j++) { maxLevel = Math.max(maxLevel, levelEvents[j].id); minLevel = Math.min(minLevel, levelEvents[j].id); } ctx.fillStyle = 'green'; ctx.globalAlpha = 0.5; ctx.fillRect(0, 0, eventLeftMargin, canvas.height); ctx.fillRect( canvas.width - eventRightMargin, 0, eventRightMargin, canvas.height ); ctx.globalAlpha = 1; x_offset = 5; y_offset = 0; ctx.fillStyle = 'black'; ctx.font = '15px Arial'; y_offset += 15; var legend = 'last bitrate:' + (bitrateEvents[bitrateEvents.length - 1].bitrate / 1000).toFixed(2) + 'Mb/s'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'min bitrate:' + (minBitrate / 1000).toFixed(2) + 'Mb/s'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'max bitrate:' + (maxBitrate / 1000).toFixed(2) + 'Mb/s'; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'min/last/max level:' + minLevel + '/' + levelEvents[levelEvents.length - 1].id + '/' + maxLevel; ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'nb level switch:' + (levelEvents.length - 1); ctx.fillText(legend, x_offset, y_offset); y_offset += 15; legend = 'average level:' + (sumLevel / sumDuration).toFixed(2); ctx.fillText(legend, x_offset, y_offset); maxBitrate *= 1.1; ctx.strokeStyle = 'blue'; ctx.beginPath(); ctx.moveTo(bufferChartStart, ctx.canvas.height); for (var k = 0; k < bitrateEvents.length; k++) { event = bitrateEvents[k]; x_offset = bufferChartStart + (bufferChartWidth * (event.time - minTime)) / (maxTime - minTime); y_offset = ctx.canvas.height * (1 - event.bitrate / maxBitrate); ctx.lineTo(x_offset, y_offset); } ctx.lineTo(bufferChartStart + bufferChartWidth, y_offset); ctx.stroke(); ctx.strokeStyle = 'black'; ctx.beginPath(); x_offset = bufferChartStart; y_offset = ctx.canvas.height; ctx.moveTo(x_offset, y_offset); for (var l = 0; l < levelEvents.length; l++) { event = levelEvents[l]; x_offset = bufferChartStart + (bufferChartWidth * (event.time - minTime)) / (maxTime - minTime); ctx.lineTo(x_offset, y_offset); y_offset = ctx.canvas.height * (1 - event.bitrate / maxBitrate); ctx.lineTo(x_offset, y_offset); } ctx.lineTo(bufferChartStart + bufferChartWidth, y_offset); ctx.stroke(); ctx.globalAlpha = 0.7; ctx.fillStyle = 'grey'; var x_start = bufferChartStart; var x_w = (bufferChartWidth * (windowMinTime - minTime)) / (maxTime - minTime); ctx.fillRect(x_start, 0, x_w, canvas.height); x_start = bufferChartStart + (bufferChartWidth * (windowMaxTime - minTime)) / (maxTime - minTime); x_w = canvas.width - x_start - eventRightMargin; ctx.fillRect(x_start, 0, x_w, canvas.height); ctx.globalAlpha = 1; } function canvasDrawLoadEvent(ctx, yoffset, event, minTime, maxTime) { var legend; var offset; var x_start; var x_w; var networkChartStart = eventLeftMargin; var networkChartWidth = ctx.canvas.width - eventLeftMargin - eventRightMargin; var tend = Math.round(event.time + event.duration + event.latency); // draw start ctx.fillStyle = 'black'; ctx.font = '12px Arial'; legend = Math.round(event.time); offset = ctx.measureText(legend).width + 5; x_start = networkChartStart - offset + (networkChartWidth * (event.time - minTime)) / (maxTime - minTime); ctx.fillText(legend, x_start, yoffset + 12); // draw latency rectangle ctx.fillStyle = 'orange'; x_start = networkChartStart + (networkChartWidth * (event.time - minTime)) / (maxTime - minTime); x_w = (networkChartWidth * event.latency) / (maxTime - minTime); ctx.fillRect(x_start, yoffset, x_w, 15); // draw download rectangle ctx.fillStyle = 'green'; x_start = networkChartStart + (networkChartWidth * (event.time + event.latency - minTime)) / (maxTime - minTime); x_w = (networkChartWidth * event.load) / (maxTime - minTime); ctx.fillRect(x_start, yoffset, x_w, 15); if (event.parsing) { // draw parsing rectangle ctx.fillStyle = 'blue'; x_start = networkChartStart + (networkChartWidth * (event.time + event.latency + event.load - minTime)) / (maxTime - minTime); x_w = (networkChartWidth * event.parsing) / (maxTime - minTime); ctx.fillRect(x_start, yoffset, x_w, 15); if (event.buffer) { // draw buffering rectangle ctx.fillStyle = 'red'; x_start = networkChartStart + (networkChartWidth * (event.time + event.latency + event.load + event.parsing - minTime)) / (maxTime - minTime); x_w = (networkChartWidth * event.buffer) / (maxTime - minTime); ctx.fillRect(x_start, yoffset, x_w, 15); } } // draw end time ctx.fillStyle = 'black'; ctx.font = '12px Arial'; legend = tend; x_start += x_w + 5; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; legend = '[' + Math.round(event.latency); ctx.fillStyle = 'orange'; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; legend = Math.round(event.load); if (!event.parsing) { legend += ']'; } ctx.fillStyle = 'green'; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; if (event.parsing) { legend = Math.round(event.parsing); if (!event.buffer) { legend += ']'; } ctx.fillStyle = 'blue'; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; if (event.buffer) { legend = Math.round(event.buffer) + ']'; ctx.fillStyle = 'red'; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; } } if (event.size) { if (event.size > 1000 * 1000) { legend = (event.size / 1000000).toFixed(1) + 'MB'; } else { legend = Math.round(event.size / 1000) + 'kB'; } ctx.fillStyle = 'black'; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; } if (event.bw) { if (event.bw > 1000) { legend = (event.bw / 1000).toFixed(1) + 'Mbps'; } else { legend = event.bw + ' kbps'; } ctx.fillStyle = 'black'; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; } // draw event name ctx.fillStyle = 'black'; ctx.font = '15px Arial'; legend = event.type; if (event.id2 !== undefined) { legend += ' ' + event.id2; } if (event.id3 !== undefined) { legend += '/' + event.id3; } if (event.id !== undefined) { if (event.type.indexOf('fragment') !== -1) { legend += ' @'; } legend += ' ' + event.id; } if (event.start !== undefined) { legend += ' [' + event.start + ',' + event.end + ']'; } ctx.fillText(legend, 5, yoffset + 15); } function canvasDrawVideoEvent(ctx, yoffset, event, minTime, maxTime) { var legend; var offset; var x_start; var x_w; var networkChartStart = eventLeftMargin; var networkChartWidth = ctx.canvas.width - eventLeftMargin - eventRightMargin; // draw event name ctx.fillStyle = 'black'; ctx.font = '15px Arial'; legend = event.type; if (event.name !== undefined) { legend += ':' + event.name; } ctx.fillText(legend, 5, yoffset + 15); // draw start time ctx.fillStyle = 'black'; ctx.font = '12px Arial'; legend = Math.round(event.time); offset = ctx.measureText(legend).width + 5; x_start = networkChartStart - offset + (networkChartWidth * (event.time - minTime)) / (maxTime - minTime); ctx.fillText(legend, x_start, yoffset + 12); // draw event rectangle x_start = networkChartStart + (networkChartWidth * (event.time - minTime)) / (maxTime - minTime); if (event.duration) { x_w = (networkChartWidth * event.duration) / (maxTime - minTime); } else { x_w = 1; } ctx.fillRect(x_start, yoffset, x_w, 15); if (event.duration) { // draw end time ctx.fillStyle = 'black'; ctx.font = '12px Arial'; legend = Math.round(event.time + event.duration); x_start += x_w + 5; ctx.fillText(legend, x_start, yoffset + 12); x_start += ctx.measureText(legend).width + 5; legend = '[' + Math.round(event.duration) + ']'; ctx.fillStyle = 'blue'; ctx.fillText(legend, x_start, yoffset + 12); } }