123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- import Chart from 'chart.js';
- // Modify horizontalBar so that each dataset (fragments, timeRanges) draws on the same row (level, track or buffer)
- Chart.controllers.horizontalBar.prototype.calculateBarValuePixels = function (
- datasetIndex,
- index,
- options
- ) {
- const chart = this.chart;
- const scale = this._getValueScale();
- const datasets = chart.data.datasets;
- if (!datasets) {
- throw new Error(`Chart datasets are ${datasets}`);
- }
- scale._parseValue = scaleParseValue;
- const obj = datasets[datasetIndex].data[index];
- const value = scale._parseValue(obj);
- const start =
- value.start === undefined
- ? 0
- : value.max >= 0 && value.min >= 0
- ? value.min
- : value.max;
- const length =
- value.start === undefined
- ? value.end
- : value.max >= 0 && value.min >= 0
- ? value.max - value.min
- : value.min - value.max;
- const base = scale.getPixelForValue(start);
- const head = scale.getPixelForValue(start + length);
- const size = head - base;
- return {
- size: size,
- base: base,
- head: head,
- center: head + size / 2,
- };
- };
- Chart.controllers.horizontalBar.prototype.calculateBarIndexPixels = function (
- datasetIndex,
- index,
- ruler,
- options
- ) {
- const rowHeight = options.barThickness;
- const size = rowHeight * options.categoryPercentage;
- const center = ruler.start + (datasetIndex * rowHeight + rowHeight / 2);
- return {
- base: center - size / 2,
- head: center + size / 2,
- center,
- size,
- };
- };
- Chart.controllers.horizontalBar.prototype.draw = function () {
- const rects = this.getMeta().data;
- const len = rects.length;
- const dataset = this.getDataset();
- if (len !== dataset.data.length) {
- // View does not match dataset (wait for redraw)
- return;
- }
- const chart = this.chart;
- const scale = this._getValueScale();
- scale._parseValue = scaleParseValue;
- const ctx: CanvasRenderingContext2D = chart.ctx;
- const chartArea: { left; top; right; bottom } = chart.chartArea;
- Chart.helpers.canvas.clipArea(ctx, chartArea);
- if (!this.lineHeight) {
- this.lineHeight =
- Math.ceil(ctx.measureText('0').actualBoundingBoxAscent) + 2;
- }
- const lineHeight = this.lineHeight;
- let range = 0;
- for (let i = 0; i < len; ++i) {
- const rect = rects[i];
- const view = rect._view;
- if (!intersects(view.base, view.x, chartArea.left, chartArea.right)) {
- // Do not draw elements outside of the chart's viewport
- continue;
- }
- const obj = dataset.data[i];
- const val = scale._parseValue(obj);
- if (!isNaN(val.min) && !isNaN(val.max)) {
- const { dataType } = obj;
- let { stats } = obj;
- const isPart = dataType === 'part';
- const isFragmentHint = dataType === 'fragmentHint';
- const isFragment = dataType === 'fragment' || isPart || isFragmentHint;
- const isCue = dataType === 'cue';
- if (isCue) {
- view.y += view.height * 0.5 * (i % 2) - view.height * 0.25;
- } else if (isPart) {
- view.height -= 22;
- }
- const bounds = boundingRects(view);
- const drawText = bounds.w > lineHeight * 1.5 && !isFragmentHint;
- if (isFragment || isCue) {
- if (drawText) {
- view.borderWidth = 1;
- if (i === 0) {
- view.borderSkipped = false;
- }
- } else {
- range =
- range ||
- scale.getValueForPixel(chartArea.right) -
- scale.getValueForPixel(chartArea.left);
- if (range > 300 || isCue) {
- view.borderWidth = 0;
- }
- }
- if (isFragmentHint) {
- view.borderWidth = 0;
- view.backgroundColor = 'rgba(0, 0, 0, 0.1)';
- } else {
- view.backgroundColor = `rgba(0, 0, 0, ${0.05 + (i % 2) / 12})`;
- }
- }
- rect.draw();
- if (isFragment) {
- if (!stats) {
- stats = {};
- }
- if (isPart) {
- ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
- ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
- }
- if (stats.aborted) {
- ctx.fillStyle = 'rgba(100, 0, 0, 0.3)';
- ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
- }
- if (stats.loaded && stats.total) {
- ctx.fillStyle = 'rgba(50, 20, 100, 0.3)';
- ctx.fillRect(
- bounds.x,
- bounds.y,
- (bounds.w * stats.loaded) / stats.total,
- bounds.h
- );
- }
- } else if (isCue) {
- if (obj.active) {
- ctx.fillStyle = 'rgba(100, 100, 10, 0.4)';
- ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);
- }
- }
- if (drawText) {
- const start = val.start; // obj.start;
- ctx.fillStyle = 'rgb(0, 0, 0)';
- if (stats) {
- const snBounds = Object.assign({}, bounds);
- if (obj.cc) {
- const ccLabel = `cc:${obj.cc}`;
- const ccWidth = Math.min(
- ctx.measureText(ccLabel).width + 2,
- snBounds.w / 2 - 2
- );
- if (ccWidth) {
- ctx.fillText(
- ccLabel,
- snBounds.x + 2,
- snBounds.y + lineHeight,
- snBounds.w / 2 - 4
- );
- snBounds.x += ccWidth;
- snBounds.w -= ccWidth;
- }
- }
- const snLabel = isPart ? `part: ${obj.index}` : `sn: ${obj.sn}`;
- const textWidth = Math.min(
- ctx.measureText(snLabel).width + 2,
- snBounds.w - 2
- );
- ctx.fillText(
- snLabel,
- snBounds.x + snBounds.w - textWidth,
- snBounds.y + lineHeight,
- snBounds.w - 4
- );
- }
- if (isCue) {
- const strLength = Math.min(
- 30,
- Math.ceil(bounds.w / (lineHeight / 3))
- );
- ctx.fillText(
- ('' + obj.content).slice(0, strLength),
- bounds.x + 2,
- bounds.y + bounds.h - 3,
- bounds.w - 5
- );
- } else if (!isPart) {
- const float = start !== (start | 0);
- const fixedDigits = float
- ? Math.min(5, Math.max(1, Math.floor(bounds.w / 10 - 1)))
- : 0;
- const startString = hhmmss(start, fixedDigits);
- ctx.fillText(
- startString,
- bounds.x + 2,
- bounds.y + bounds.h - 3,
- bounds.w - 5
- );
- }
- }
- }
- }
- Chart.helpers.canvas.unclipArea(chart.ctx);
- };
- export function applyChartInstanceOverrides(chart) {
- Object.keys(chart.scales).forEach((axis) => {
- const scale = chart.scales![axis];
- scale._parseValue = scaleParseValue;
- });
- }
- function scaleParseValue(value: number[] | any) {
- if (value === undefined) {
- console.warn('Chart values undefined (update chart)');
- return {};
- }
- let start;
- let end;
- let min;
- let max;
- if (Array.isArray(value)) {
- start = +this.getRightValue(value[0]);
- end = +this.getRightValue(value[1]);
- min = Math.min(start, end);
- max = Math.max(start, end);
- } else {
- start = +this.getRightValue(value.start);
- if ('end' in value) {
- end = +this.getRightValue(value.end);
- } else {
- end = +this.getRightValue(value.start + value.duration);
- }
- min = Math.min(start, end);
- max = Math.max(start, end);
- }
- return {
- min,
- max,
- start,
- end,
- };
- }
- function intersects(x1, x2, x3, x4) {
- return x2 > x3 && x1 < x4;
- }
- function boundingRects(vm) {
- const half = vm.height / 2;
- const left = Math.min(vm.x, vm.base);
- const right = Math.max(vm.x, vm.base);
- const top = vm.y - half;
- const bottom = vm.y + half;
- return {
- x: left,
- y: top,
- w: right - left,
- h: bottom - top,
- };
- }
- export function hhmmss(value, fixedDigits) {
- const h = (value / 3600) | 0;
- const m = ((value / 60) | 0) % 60;
- const s = value % 60;
- return `${h}:${pad(m, 2)}:${pad(
- s.toFixed(fixedDigits),
- fixedDigits ? fixedDigits + 3 : 2
- )}`.replace(/^(?:0+:?)*(\d.*?)(?:\.0*)?$/, '$1');
- }
- function pad(str, length) {
- str = '' + str;
- while (str.length < length) {
- str = '0' + str;
- }
- return str;
- }
|