window.ReplayTimelineCanvas = (function () {
|
function ReplayTimelineCanvas(options) {
|
options = options || {};
|
this.canvas = options.canvas || null;
|
this.context = null;
|
this.lastWidth = 0;
|
this.lastHeight = 0;
|
this.lastDpr = 0;
|
}
|
|
ReplayTimelineCanvas.prototype.setCanvas = function (canvas) {
|
this.canvas = canvas || null;
|
this.context = null;
|
this.lastWidth = 0;
|
this.lastHeight = 0;
|
this.lastDpr = 0;
|
};
|
|
ReplayTimelineCanvas.prototype.draw = function (state) {
|
var canvas = this.canvas;
|
if (!canvas) {
|
return;
|
}
|
var width = Math.max(1, Math.floor(canvas.clientWidth || 0));
|
var height = Math.max(1, Math.floor(canvas.clientHeight || 0));
|
var dpr = Math.min(window.devicePixelRatio || 1, 2);
|
this.ensureSurface(width, height, dpr);
|
if (!this.context) {
|
return;
|
}
|
this.context.setTransform(dpr, 0, 0, dpr, 0, 0);
|
this.context.clearRect(0, 0, width, height);
|
|
var buckets = state && Array.isArray(state.buckets) ? state.buckets : [];
|
this.drawBase(width, height, buckets);
|
if (!buckets.length) {
|
return;
|
}
|
|
this.drawBucketBands(width, height, buckets);
|
this.drawSelectionBand(width, height, buckets.length, state && state.selectedBucketIndex, 'rgba(111, 149, 189, 0.18)', 'rgba(111, 149, 189, 0.46)');
|
this.drawSelectionBand(width, height, buckets.length, state && state.hoverBucketIndex, 'rgba(111, 149, 189, 0.12)', 'rgba(111, 149, 189, 0.28)', state && state.selectedBucketIndex);
|
this.drawCurrentMarker(width, height, state && state.currentMarkerRatio);
|
};
|
|
ReplayTimelineCanvas.prototype.ensureSurface = function (width, height, dpr) {
|
var canvas = this.canvas;
|
if (!canvas) {
|
this.context = null;
|
return;
|
}
|
if (this.lastWidth === width && this.lastHeight === height && this.lastDpr === dpr && this.context) {
|
return;
|
}
|
canvas.width = Math.max(1, Math.floor(width * dpr));
|
canvas.height = Math.max(1, Math.floor(height * dpr));
|
canvas.style.width = width + 'px';
|
canvas.style.height = height + 'px';
|
this.context = canvas.getContext('2d');
|
this.lastWidth = width;
|
this.lastHeight = height;
|
this.lastDpr = dpr;
|
};
|
|
ReplayTimelineCanvas.prototype.drawBase = function (width, height, buckets) {
|
this.context.fillStyle = buckets.length ? 'rgba(255, 255, 255, 0)' : '#eef3f8';
|
this.context.fillRect(0, 0, width, height);
|
};
|
|
ReplayTimelineCanvas.prototype.drawBucketBands = function (width, height, buckets) {
|
var bandTop = 16;
|
var bandHeight = Math.max(1, height - 32);
|
var markerTop = 10;
|
var markerHeight = 4;
|
var bucketWidth = width / buckets.length;
|
for (var index = 0; index < buckets.length; index++) {
|
var bucket = buckets[index];
|
var left = index * bucketWidth;
|
var drawWidth = Math.max(1, Math.ceil(bucketWidth));
|
this.context.fillStyle = this.resolveBucketFillColor(bucket);
|
this.context.fillRect(left, bandTop, drawWidth, bandHeight);
|
if (bucket.abnormalCount > 0) {
|
this.context.fillStyle = this.resolveBucketEventColor(bucket);
|
this.context.fillRect(left, markerTop, drawWidth, markerHeight);
|
}
|
}
|
};
|
|
ReplayTimelineCanvas.prototype.drawSelectionBand = function (width, height, bucketCount, bucketIndex, fillStyle, borderStyle, ignoreBucketIndex) {
|
if (!(bucketIndex >= 0) || !bucketCount || bucketIndex === ignoreBucketIndex) {
|
return;
|
}
|
var bandWidth = width / bucketCount;
|
var left = bucketIndex * bandWidth;
|
var snappedLeft = this.snapPixel(left);
|
var snappedRight = this.snapPixel(left + bandWidth);
|
var drawWidth = Math.max(1, snappedRight - snappedLeft);
|
this.context.fillStyle = fillStyle;
|
this.context.fillRect(snappedLeft, 0, drawWidth, height);
|
this.context.strokeStyle = borderStyle;
|
this.context.lineWidth = 1;
|
this.context.beginPath();
|
this.context.moveTo(snappedLeft + 0.5, 0);
|
this.context.lineTo(snappedLeft + 0.5, height);
|
this.context.moveTo(snappedLeft + drawWidth - 0.5, 0);
|
this.context.lineTo(snappedLeft + drawWidth - 0.5, height);
|
this.context.stroke();
|
};
|
|
ReplayTimelineCanvas.prototype.drawCurrentMarker = function (width, height, currentMarkerRatio) {
|
if (!(currentMarkerRatio >= 0)) {
|
return;
|
}
|
var markerLeft = this.snapPixel((width - 1) * Math.max(0, Math.min(1, currentMarkerRatio)));
|
this.context.fillStyle = 'rgba(47, 80, 112, 0.88)';
|
this.context.fillRect(markerLeft, 0, 2, height);
|
};
|
|
ReplayTimelineCanvas.prototype.resolveBucketFillColor = function (bucket) {
|
if (!bucket || !bucket.hasReplayData) {
|
return '#e5ecf3';
|
}
|
var intensity = Math.max(0, Math.min(100, Number(bucket.activityScore || 0))) / 100;
|
var blueChannel = Math.round(255 - intensity * 82);
|
var greenChannel = Math.round(236 - intensity * 76);
|
return 'rgb(47,' + greenChannel + ',' + blueChannel + ')';
|
};
|
|
ReplayTimelineCanvas.prototype.resolveBucketEventColor = function (bucket) {
|
var eventType = String(bucket && bucket.topEventType || '').toUpperCase();
|
if (eventType === 'ERROR') {
|
return '#ff6b57';
|
}
|
if (eventType === 'BLOCK') {
|
return '#ffb347';
|
}
|
return '#ffd84d';
|
};
|
|
ReplayTimelineCanvas.prototype.snapPixel = function (value) {
|
return Math.round(Number(value) || 0);
|
};
|
|
ReplayTimelineCanvas.prototype.destroy = function () {
|
this.canvas = null;
|
this.context = null;
|
this.lastWidth = 0;
|
this.lastHeight = 0;
|
this.lastDpr = 0;
|
};
|
|
return ReplayTimelineCanvas;
|
})();
|