ngx-video-timeline
Version:
a video timeline for ng2+
823 lines • 107 kB
JavaScript
import { NgStyle } from '@angular/common';
import { Component, EventEmitter, HostListener, Input, Output, ViewChild } from '@angular/core';
import { interval } from 'rxjs';
import { DateUtil } from './untils/date-util';
import * as i0 from "@angular/core";
export class NgxVideoTimelineComponent {
// The height of the outer canvas
canvasHeight = 50;
// Canvas scale is adjusted according to outer height
scale = this.canvasHeight / 4.55;
// Video playback time
playTime;
// The video plays at twice the speed
speed;
// Video fast forward value
forWardValue;
// Start time limit: Timestamp
startTimeThreshold;
// End time limit: Timestamp
endTimeThreshold;
// relation to Css Start
// color of canvas border
borderColor;
// color of canvas backgraound
bgColor;
// color of the bottomLine
bottomLineColor;
// color of the verticalBar
verticalBarColor;
// color of the playBar
playBarColor;
// relation to Css End
// Video clips
videoCells;
// flag of click play button
isPlayClick;
// emit data when click playButton
playClick;
// emit data when mouseUp
mouseUp;
// emit data when mouseDown
mouseDown;
// emit data when keyUp
keyUp;
// emit data when keyDown
keyDown;
// --- canvas data start ---//
// canvas box
canvas;
// canvas context
ctx;
// canvas width
canvasW;
// canvas height
canvasH;
// video clips in reality
timecell;
// per minute stand for step
minutesPerStep;
// per minite stand for px
pxPerMs;
// Minimum width between scales, unit px
graduationStep;
// The timeline shows x hours
hoursPerRuler;
// The leftmost timestamp that appears -- the default is the first 12 hours
startTimestamp;
// current timestamp
currentTimestamp;
// Px two hours apart
distanceBetweenGtitle;
// zoom of canvas
zoom;
// marker of drag an unreleased mouse event
gIsMousedown;
// marker of drag the mouse move
gIsMousemove;
// The position of the X-axis when the mouse is pressed
gMousedownCursor = undefined;
// The position of the y-axis when the mouse is pressed
gMousedownCursorY = undefined;
// Time flow timer
setTimeMove;
// The distance to the left of the play button
playBarDistanceLeft;
// Play the initial position of the icon
playBarOffsetX;
// Play the X-axis position 1 of the icon
playBarOffsetX1;
// Play the X-axis position 2 of the icon
playBarOffsetX2;
// Play the Y-axis position 1 of the icon
playBarOffsetY1;
// Play the Y-axis position 2 of the icon
playBarOffsetY2;
// --- canvas data end ---//
// elements of the timeline
canvasExp;
constructor() {
// this.startTimeThreshold = new Date().getTime() - 1 * 0.5 * 3600 * 1000;
// this.endTimeThreshold = new Date().getTime() + 1 * 1 * 3600 * 1000;
this.forWardValue = 5000;
this.speed = 1000;
this.playTime = new Date().getTime();
this.startTimeThreshold = new Date().getTime() - 1 * 12 * 3600 * 1000;
this.endTimeThreshold = new Date().getTime() + 1 * 12 * 3600 * 1000;
this.playClick = new EventEmitter();
this.mouseUp = new EventEmitter();
this.mouseDown = new EventEmitter();
this.keyUp = new EventEmitter();
this.keyDown = new EventEmitter();
this.isPlayClick = false;
this.videoCells = [
{
beginTime: new Date().getTime() - 3 * 3600 * 1000,
endTime: new Date().getTime() - 1 * 3600 * 1000,
style: {
background: 'rgba(132, 244, 180, 0.498039)'
}
},
{
beginTime: new Date().getTime() - 6 * 3600 * 1000,
endTime: new Date().getTime() - 4 * 3600 * 1000,
style: {
background: 'rgba(132, 244, 180, 0.498039)'
}
}
];
this.verticalBarColor = 'rgba(0,0,0,1)';
this.bottomLineColor = 'rgba(0,0,0,1)';
this.borderColor = '#fff';
this.bgColor = '#fff';
this.playBarColor = '#448aff';
}
/**
* Browser change event
*/
onResize() {
this.canvas.width = Math.round(this.canvas.parentNode.offsetWidth - 2);
this.canvasW = this.canvas.parentNode.offsetWidth;
this.init(this.startTimestamp, this.timecell, false);
}
/**
* Keyboard press event
*/
onKeyDown(event) {
if (Number(event.keyCode) === 37) {
this.playTime = Number(this.playTime) - this.forWardValue;
this.currentTimestamp = Number(this.currentTimestamp) - this.forWardValue;
this.set_time_to_middle(this.playTime);
}
else if (Number(event.keyCode === 39)) {
this.playTime = Number(this.playTime) + this.forWardValue;
this.currentTimestamp = Number(this.currentTimestamp) + this.forWardValue;
this.set_time_to_middle(this.playTime);
}
this.keyDown.emit(this.playTime);
}
/**
* Keyboard release event
*/
onKeyUp(event) {
if (Number(event.keyCode) === 13 || Number(event.keyCode === 32)) {
this.isPlayClick ? this.onPauseClick() : this.onPlayClick();
}
this.keyUp.emit(this.playTime);
}
ngOnInit() {
// Initialize data video group event stamp to show new Date().getTime()- number of hours
// Assign the Canvas DOM to the variable Canvas
this.canvas = this.canvasExp.nativeElement;
// Define the area of the canvas
this.ctx = this.canvas.getContext('2d');
// Redefine the width of the canvas. The default canvas is 300. Assign the width of the parent element
this.canvas.width = Math.round(this.canvas.parentNode.offsetWidth - 2);
// Store the width and height of the canvas
this.canvasW = this.canvas.width;
this.canvas.height = this.canvasHeight;
this.canvasH = this.canvas.height;
// Assign the video array to Timecell
this.timecell = this.videoCells;
// Initialize the number of steps per minute
this.minutesPerStep = [
1,
2,
5,
10,
15,
20,
30,
60,
120,
180,
240,
360,
720,
1440
];
// Initialization style
// Minimum width between scales, in units of px 20px
this.graduationStep = 20;
// The timeline shows the time rounded up according to the time threshold
this.hoursPerRuler = Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600) < 24 ?
Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600) :
24;
// The leftmost timestamp defaults to 12 hours before the current time
this.startTimestamp = Number(this.startTimeThreshold);
// Default distance 80
this.distanceBetweenGtitle = 80;
// Default zoom 24
this.zoom = 24;
// Default false
this.gIsMousedown = false;
this.gIsMousemove = false;
this.gMousedownCursor = undefined;
// px/ms
this.pxPerMs = this.canvasW / (this.hoursPerRuler * 3600 * 1000);
// The initial X position of the playback icon is in the middle of the scale
this.playBarOffsetX = this.canvasW / 2;
this.playBarDistanceLeft = this.playBarOffsetX / this.pxPerMs / 3600 / 1000 / this.hoursPerRuler;
this.currentTimestamp = this.startTimestamp + this.hoursPerRuler * this.playBarDistanceLeft * 3600 * 1000;
this.playBarOffsetX1 = this.playBarOffsetX - (this.scale * 0.6);
this.playBarOffsetX2 = this.playBarOffsetX + (this.scale * 0.6);
this.playBarOffsetY1 = (this.scale * 2.5);
this.playBarOffsetY2 = ((this.scale * 3.5));
// Initialize the timeline
this.init(this.startTimestamp, this.timecell, false);
// Draw the play button
this.drawPalyBar();
}
ngOnChanges(changes) {
// Refactor the playback component when the width and height change
if (changes.canvasHeight) {
this.canvasHeight = changes.canvasHeight.currentValue;
// Assign the Canvas DOM to the variable Canvas
this.canvas = this.canvasExp.nativeElement;
// Define the area of the canvas
this.ctx = this.canvas.getContext('2d');
// Redefine the width of the canvas. The default canvas is 300. Assign the width of the parent element
this.canvas.width = Math.round(this.canvas.parentNode.offsetWidth - 2);
// Store the width and height of the canvas
this.canvasW = this.canvas.width;
this.canvas.height = this.canvasHeight;
this.canvasH = this.canvas.height;
// Assign the video array to Timecell
this.timecell = this.videoCells;
this.minutesPerStep = [
1,
2,
5,
10,
15,
20,
30,
60,
120,
180,
240,
360,
720,
1440
];
// The timeline shows the time rounded up according to the time threshold
this.hoursPerRuler = Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600) < 24 ?
Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600)
: 24;
// The leftmost timestamp defaults to 12 hours before the current time
this.startTimestamp = Number(this.startTimeThreshold);
this.pxPerMs = this.canvasW / (this.hoursPerRuler * 3600 * 1000);
// The initial X position of the playback icon is in the middle of the scale
this.playBarOffsetX = this.canvasW / 2;
this.playBarDistanceLeft = this.playBarOffsetX / this.pxPerMs / 3600 / 1000 / this.hoursPerRuler;
// Current timestamp
this.currentTimestamp = this.startTimestamp + this.hoursPerRuler * this.playBarDistanceLeft * 3600 * 1000;
this.playBarOffsetX1 = this.playBarOffsetX - (this.scale * 0.6);
this.playBarOffsetX2 = this.playBarOffsetX + (this.scale * 0.6);
this.playBarOffsetY1 = (this.scale * 2.5);
this.playBarOffsetY2 = ((this.scale * 3.5));
this.init(this.startTimestamp, this.timecell, false);
this.drawPalyBar();
}
if (changes.videoCells) {
this.videoCells = changes.videoCells.currentValue;
this.timecell = this.videoCells;
this.add_cells(this.timecell);
// this.init(this.startTimestamp, this.timecell, true);
// this.drawPalyBar();
}
if (changes.startTimeThreshold) {
const value = changes.startTimeThreshold.currentValue;
if (changes.startTimeThreshold.currentValue instanceof String) {
this.startTimeThreshold = new Date(value).getTime();
}
else if (value instanceof Date) {
this.startTimeThreshold = value.getTime();
}
else if (typeof value === 'number') {
this.startTimeThreshold = Number(value);
}
this.hoursPerRuler = Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600) < 24
? Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600)
: 24;
this.startTimestamp = Number(this.startTimeThreshold);
// this.init(this.startTimestamp, this.timecell, false);
}
if (changes.endTimeThreshold) {
const value = changes.endTimeThreshold.currentValue;
if (changes.endTimeThreshold.currentValue instanceof String) {
this.endTimeThreshold = new Date(value).getTime();
}
else if (value instanceof Date) {
this.endTimeThreshold = value.getTime();
}
else if (typeof value === 'number') {
this.endTimeThreshold = Number(value);
}
this.hoursPerRuler = Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600) < 24
? Math.ceil((Number(this.endTimeThreshold) - Number(this.startTimeThreshold)) / 1000 / 3600)
: 24;
}
if (changes.playTime) {
const value = changes.playTime.currentValue;
if (changes.playTime.currentValue instanceof String) {
this.playTime = new Date(value).getTime();
}
else if (value instanceof Date) {
this.playTime = value.getTime();
}
else if (typeof value === 'number') {
this.playTime = Number(value);
}
// use SetTimeOut Timer to make it asynchronous
setTimeout(() => {
this.set_time_to_middle(new Date(this.playTime).getTime());
}, 100);
}
if (changes.speed) {
this.speed = Number(changes.speed.currentValue) * 1000;
}
if (changes.forWardValue) {
this.forWardValue = Number(changes.forWardValue.currentValue) * 1000;
}
if (changes.isPlayClick) {
if (changes.isPlayClick.currentValue) {
this.onPlayClick();
}
else {
this.onPauseClick();
}
}
}
/**
* Initialize
* @param startTimestamp Leftmost time
* @param timecell Video segment array
* @param redrawFlag Whether to redraw the mark
*/
init(startTimestamp, timecell, redrawFlag) {
this.timecell = timecell;
this.startTimestamp = startTimestamp;
if (this.currentTimestamp >=
Number(this.endTimeThreshold)) {
this.startTimestamp =
Number(this.endTimeThreshold) -
(this.hoursPerRuler * this.playBarDistanceLeft * 1000 * 3600);
this.currentTimestamp =
Number(this.startTimestamp) + (this.hoursPerRuler * this.playBarDistanceLeft * 1000 * 3600);
this.playTime =
Number(this.startTimestamp) + (this.hoursPerRuler * this.playBarDistanceLeft * 1000 * 3600);
}
else if (this.currentTimestamp <=
Number(this.startTimeThreshold)) {
this.startTimestamp =
Number(this.startTimeThreshold) -
(this.hoursPerRuler * this.playBarDistanceLeft * 1000 * 3600);
this.currentTimestamp =
Number(this.startTimestamp) + (this.hoursPerRuler * this.playBarDistanceLeft * 1000 * 3600);
this.playTime =
Number(this.startTimestamp) + (this.hoursPerRuler * this.playBarDistanceLeft * 1000 * 3600);
}
this.drawCellBg();
this.add_graduations(startTimestamp);
this.add_cells(timecell);
// Draw the verticalBar
this.drawLine(0, this.canvasH, this.canvasW, this.canvasH, this.bottomLineColor, 1);
}
/**
* Draw add scale
* @param startTimestamp Leftmost time
*/
add_graduations(startTimestamp) {
// px/min
const pxPerMin = this.canvasW / (this.hoursPerRuler * 60);
// px/ms
const pxPerMs = this.canvasW / (this.hoursPerRuler * 60 * 60 * 1000);
// The default minimum value of PX/steo is 20px
let pxPerStep = this.graduationStep;
// Min/steo
let minPerStep = pxPerStep / pxPerMin;
for (const v of this.minutesPerStep) {
if (minPerStep <= v) {
// Keep each cell within the range specified by minutesPerStep
minPerStep = v;
pxPerStep = pxPerMin * minPerStep;
break;
}
}
let mediumStep = 30;
for (const v of this.minutesPerStep) {
if (this.distanceBetweenGtitle / pxPerMin <= v) {
mediumStep = v;
break;
}
}
// The total number
const numSteps = this.canvasW / pxPerStep;
let graduationLeft;
let graduationTime;
let caretClass;
let lineH;
// The initial offset time (ms)
const msOffset = this.ms_to_next_step(startTimestamp, minPerStep * 60 * 1000);
// The initial offset is (px)
const pxOffset = msOffset * pxPerMs;
// ms/step
const msPerStep = pxPerStep / pxPerMs;
for (let i = 0; i < numSteps; i++) {
// Distance = offset distance to start + steps *px/ steps
graduationLeft = pxOffset + i * pxPerStep;
// Time = left start time + offset time + steps *ms/ steps
graduationTime =
Number(startTimestamp) +
Number(msOffset) +
i * Number(msPerStep);
const date = new Date(graduationTime);
if (date.getUTCHours() === 0 && date.getUTCMinutes() === 0) {
caretClass = 'big';
lineH = (this.scale * 1.25);
const bigDate = DateUtil.formatDate(date, 'HH:mm:ss');
this.ctx.textAlign = 'center';
this.ctx.fillText(bigDate, graduationLeft, (this.scale * 1.5));
this.ctx.fillStyle = this.verticalBarColor;
}
else if ((graduationTime / (60 * 1000)) % mediumStep === 0) {
caretClass = 'middle';
lineH = (this.scale * 0.75);
const middleDate = DateUtil.formatDate(date, 'HH:mm:ss');
this.ctx.textAlign = 'center';
this.ctx.fillText(middleDate, graduationLeft, (this.scale * 1.5));
this.ctx.fillStyle = this.verticalBarColor;
}
else {
lineH = (this.scale * 0.5);
}
// drawLine(graduationLeft,0,graduationLeft,lineH,"rgba(151,158,167,0.4)",1);
this.drawLine(graduationLeft, 0, graduationLeft, lineH, this.verticalBarColor, 1);
}
}
/**
* Draw the play button
*/
drawPalyBar() {
this.ctx.beginPath();
this.ctx.moveTo(this.playBarOffsetX, 0);
this.ctx.lineTo(this.playBarOffsetX, (this.scale * 1.75));
this.ctx.strokeStyle = this.playBarColor;
this.ctx.stroke();
this.ctx.moveTo(this.playBarOffsetX, (this.scale * 1.75));
this.ctx.lineTo(this.playBarOffsetX, (this.scale * 1.75));
this.ctx.lineTo(this.playBarOffsetX - (this.scale * 0.6), (this.scale * 2.5));
this.ctx.lineTo(this.playBarOffsetX - (this.scale * 0.6), (this.scale * 3.5));
this.ctx.lineTo(this.playBarOffsetX + (this.scale * 0.6), (this.scale * 3.5));
this.ctx.lineTo(this.playBarOffsetX + (this.scale * 0.6), (this.scale * 2.5));
this.ctx.lineTo(this.playBarOffsetX, (this.scale * 1.75));
this.ctx.fillStyle = this.playBarColor;
this.ctx.fill();
this.ctx.closePath();
// this.init(this.startTimestamp, this.timecell, false);
const time = Number(this.currentTimestamp);
this.ctx.fillStyle = this.playBarColor;
this.ctx.textAlign = 'center';
this.ctx.fillText(DateUtil.formatDate(new Date(time), 'YYYY-MM-DD HH:mm:ss'), this.playBarOffsetX, (this.scale * 4.25));
}
/**
* Draw the line
* @param beginX The X-axis to start with
* @param beginY The Y-axis to start with
* @param endX The end of the X-axis
* @param endY The end of the Y-axis
* @param color color
* @param width width
*/
drawLine(beginX, beginY, endX, endY, color, width) {
this.ctx.beginPath();
this.ctx.moveTo(beginX, beginY);
this.ctx.lineTo(endX, endY);
this.ctx.strokeStyle = color;
this.ctx.lineWidth = width;
this.ctx.stroke();
}
/**
* Add video segment
* @param cells Video array
*/
add_cells(cells) {
cells.forEach((cell) => {
this.draw_cell(cell);
});
}
/**
* Draw video blocks
* @param cell The cell includes beginTime Ms; The endTime ms; style;
*/
draw_cell(cell) {
const pxPerMs = this.canvasW / (this.hoursPerRuler * 60 * 60 * 1000); // px/ms
const beginX = (cell.beginTime - this.startTimestamp) * pxPerMs;
const cellWidth = (cell.endTime - cell.beginTime) * pxPerMs;
this.ctx.fillStyle = cell.style.background;
this.ctx.fillRect(beginX, 0, cellWidth, (this.scale * 0.75));
}
/**
* Draws the background of the video block
*/
drawCellBg() {
this.ctx.fillStyle = 'rgba(69, 72, 76, 0.5)';
this.ctx.fillRect(0, 0, this.canvasW, 0);
}
/**
* Drag/click the Mousedown event
*/
mousedownFunc(e) {
this.gIsMousedown = true;
this.gMousedownCursor = this.get_cursor_x_position(e).posX;
this.gMousedownCursorY = this.get_cursor_x_position(e).posY;
}
/**
* Drag/mouse hover to display mousemove events
*/
mousemoveFunc(e) {
this.clearCanvas();
const posX = this.get_cursor_x_position(e).posX;
const pxPerMs = this.canvasW / (this.hoursPerRuler * 3600 * 1000);
const diffX = posX - this.gMousedownCursor;
if (this.gIsMousedown) {
if (this.gMousedownCursor >= this.playBarOffsetX1 &&
this.gMousedownCursor <= this.playBarOffsetX2 &&
this.gMousedownCursorY >= this.playBarOffsetY1 &&
this.gMousedownCursorY <= this.playBarOffsetY2) {
// this.playBarDistanceLeft = this.playBarOffsetX / this.pxPerMs / 3600 / 1000 / this.hoursPerRuler;
// this.playBarOffsetX = posX;
// this.playBarOffsetX1 = this.playBarOffsetX - (this.scale * 0.6);
// this.playBarOffsetX2 = this.playBarOffsetX + (this.scale * 0.6);
this.startTimestamp =
this.startTimestamp + Math.round(diffX / pxPerMs);
this.currentTimestamp =
(this.startTimestamp +
Math.round(this.playBarOffsetX / pxPerMs));
this.drawPalyBar();
this.init(this.startTimestamp, this.timecell, false);
this.gIsMousemove = true;
}
else {
this.startTimestamp =
this.startTimestamp - Math.round(diffX / pxPerMs);
this.currentTimestamp =
this.startTimestamp +
Math.round(this.playBarOffsetX / pxPerMs);
this.drawPalyBar();
this.init(this.startTimestamp, this.timecell, true);
this.gIsMousemove = true;
this.gMousedownCursor = posX;
}
this.mouseUp.emit(this.currentTimestamp);
}
else {
const time = this.startTimestamp + posX / pxPerMs;
this.drawPalyBar();
this.init(this.startTimestamp, this.timecell, true);
this.drawLine(posX, 0, posX, 50, 'rgb(194, 202, 215)', 1);
this.ctx.fillStyle = 'rgb(194, 202, 215)';
this.ctx.textAlign = 'center';
this.ctx.fillText(DateUtil.formatDate(new Date(time), 'YYYY-MM-DD HH:mm:ss'), posX, (this.scale * 3));
}
}
/**
* Drag/click the Mouseup event
*/
mouseupFunc(e) {
if (this.gIsMousemove) {
// Drag events
this.gIsMousemove = false;
this.gIsMousedown = false;
this.playTime =
this.startTimestamp + this.hoursPerRuler * this.playBarDistanceLeft * 3600 * 1000;
}
else {
// Click event
this.gIsMousedown = false;
// Mouse distance (px)
const posx = this.get_cursor_x_position(e).posX;
// ms/px
const msPerPx = (this.zoom * 3600 * 1000) / this.canvasW;
this.playTime = this.startTimestamp + posx * msPerPx;
this.set_time_to_middle(this.playTime);
}
this.mouseDown.emit(this.playTime);
}
/**
* Mouseout of the hidden time mouseout event
*/
mouseoutFunc() {
this.clearCanvas();
// px/ms
const pxPerMs = this.canvasW / (this.hoursPerRuler * 3600 * 1000);
this.currentTimestamp =
this.startTimestamp +
Math.round(this.playBarOffsetX / pxPerMs);
this.drawPalyBar();
this.init(this.startTimestamp, this.timecell, true);
}
/**
* Scroll to the center of the timeline for the mousewheel event
*/
mousewheelFunc(event) {
if (event && event.preventDefault) {
event.preventDefault();
}
else {
window.event.returnValue = false;
return false;
}
const e = window.event || event;
const delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail));
// Ms Remember the current middle time
const middleTime = this.startTimestamp + (this.hoursPerRuler * this.playBarDistanceLeft * 3600 * 1000);
if (delta < 0) {
this.zoom = this.zoom + 4;
if (this.zoom >= 24) {
// Shrink to a minimum of 24 hours
this.zoom = 24;
}
this.hoursPerRuler = this.zoom;
}
else if (delta > 0) {
// amplification
this.zoom = this.zoom - 4;
if (this.zoom <= 1) {
// Zoom in at most one hour
this.zoom = 1;
}
this.hoursPerRuler = this.zoom;
}
this.clearCanvas();
// // startTimestamp = current middle time - zoom /2
this.startTimestamp =
middleTime - (this.hoursPerRuler * 3600 * 1000) / 2;
this.init(this.startTimestamp, this.timecell, true);
this.drawPalyBar();
}
/**
* Get the mouse POSx
* @param e event
*/
get_cursor_x_position(e) {
let posx = 0;
let posy = 0;
if (!e) {
e = window.event;
}
if (e.offsetX || e.offsetY) {
posx = e.offsetX;
posy = e.offsetY;
}
return { posX: posx, posY: posy };
}
/**
* The offset of the left start time, returns the unit ms
* @param timestamp The time stamp
* @param step The offset
*/
ms_to_next_step(timestamp, step) {
const remainder = timestamp % step;
return remainder ? step - remainder : 0;
}
/**
* Set the time to jump to the middle red line
* @param time Unit of ms
*/
set_time_to_middle(time) {
if (this.ctx) {
this.clearCanvas();
this.startTimestamp = time - (this.hoursPerRuler * this.playBarDistanceLeft * 3600 * 1000);
this.currentTimestamp = time;
this.drawPalyBar();
this.init(this.startTimestamp, this.timecell, true);
}
}
/**
* To redraw on a canvas, it must first be cleared.
*/
clearCanvas() {
this.ctx.clearRect(0, 0, this.canvasW, (this.scale * 7.5));
}
/**
* Click to play
*/
onPlayClick() {
// this.setTimeMove = undefined;
this.isPlayClick = true;
this.setTimeMove = interval(this.speed).subscribe((d) => {
this.playTime = Number(this.playTime) + 1 * 1000;
this.playClick.emit(this.playTime);
this.set_time_to_middle(this.playTime);
});
}
/**
* Click on the pause
*/
onPauseClick() {
this.isPlayClick = false;
if (this.setTimeMove) {
// this.setTimeMove = undefined;
this.setTimeMove.unsubscribe();
this.playClick.emit(this.playTime);
}
}
/**
* Change video segment
*/
changeVideo() {
const cells = [
{
beginTime: new Date().getTime() - 1 * 1000 * 3600,
endTime: new Date().getTime() + 2 * 1000 * 3600,
style: {
background: 'rgba(132, 244, 180, 0.498039)'
}
}
];
this.clearCanvas();
this.drawPalyBar();
this.init(this.startTimestamp, cells, true);
}
/**
* Temporary unused
* @param event MatDatepickerInputEvent(Date)
*/
selectedTime(event) {
const timestamp = new Date(event.value.getTime());
this.set_time_to_middle(Number(timestamp));
}
/**
* Temporary unused
* @param event MouseEvent
*/
onDragStart(e) {
e.preventDefault();
return false;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.5", ngImport: i0, type: NgxVideoTimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.5", type: NgxVideoTimelineComponent, isStandalone: true, selector: "ngx-video-timeline", inputs: { canvasHeight: "canvasHeight", playTime: "playTime", speed: "speed", forWardValue: "forWardValue", startTimeThreshold: "startTimeThreshold", endTimeThreshold: "endTimeThreshold", borderColor: "borderColor", bgColor: "bgColor", bottomLineColor: "bottomLineColor", verticalBarColor: "verticalBarColor", playBarColor: "playBarColor", videoCells: "videoCells", isPlayClick: "isPlayClick" }, outputs: { playClick: "playClick", mouseUp: "mouseUp", mouseDown: "mouseDown", keyUp: "keyUp", keyDown: "keyDown" }, host: { listeners: { "window:resize": "onResize()", "window:keydown": "onKeyDown($event)", "window:keyup": "onKeyUp($event)" } }, viewQueries: [{ propertyName: "canvasExp", first: true, predicate: ["timeline"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `<canvas #timeline class="canvas" [ngStyle]="{cursor: 'pointer',border: '1px solid',borderColor: borderColor,'backgroundColor': bgColor}"
(dragstart)="onDragStart($event)" (mouseup)="mouseupFunc($event)" (mousewheel)="mousewheelFunc($event)"
(mousedown)="mousedownFunc($event)" (mousemove)="mousemoveFunc($event)" (mouseout)="mouseoutFunc()"></canvas>
`, isInline: true, styles: [".canvas{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.5", ngImport: i0, type: NgxVideoTimelineComponent, decorators: [{
type: Component,
args: [{ imports: [
NgStyle
], selector: 'ngx-video-timeline', template: `<canvas #timeline class="canvas" [ngStyle]="{cursor: 'pointer',border: '1px solid',borderColor: borderColor,'backgroundColor': bgColor}"
(dragstart)="onDragStart($event)" (mouseup)="mouseupFunc($event)" (mousewheel)="mousewheelFunc($event)"
(mousedown)="mousedownFunc($event)" (mousemove)="mousemoveFunc($event)" (mouseout)="mouseoutFunc()"></canvas>
`, standalone: true, styles: [".canvas{width:100%;height:100%}\n"] }]
}], ctorParameters: () => [], propDecorators: { canvasHeight: [{
type: Input
}], playTime: [{
type: Input
}], speed: [{
type: Input
}], forWardValue: [{
type: Input
}], startTimeThreshold: [{
type: Input
}], endTimeThreshold: [{
type: Input
}], borderColor: [{
type: Input
}], bgColor: [{
type: Input
}], bottomLineColor: [{
type: Input
}], verticalBarColor: [{
type: Input
}], playBarColor: [{
type: Input
}], videoCells: [{
type: Input
}], isPlayClick: [{
type: Input
}], playClick: [{
type: Output
}], mouseUp: [{
type: Output
}], mouseDown: [{
type: Output
}], keyUp: [{
type: Output
}], keyDown: [{
type: Output
}], canvasExp: [{
type: ViewChild,
args: ['timeline', { static: true }]
}], onResize: [{
type: HostListener,
args: ['window:resize', []]
}], onKeyDown: [{
type: HostListener,
args: ['window:keydown', ['$event']]
}], onKeyUp: [{
type: HostListener,
args: ['window:keyup', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZWxpbmUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvdGltZWxpbmUvc3JjL2xpYi90aW1lbGluZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFDTCxTQUFTLEVBRVQsWUFBWSxFQUNaLFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUNOLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUM5QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7O0FBbUI5QyxNQUFNLE9BQU8seUJBQXlCO0lBR3BDLGlDQUFpQztJQUN4QixZQUFZLEdBQUcsRUFBRSxDQUFDO0lBRTNCLHFEQUFxRDtJQUNyRCxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUM7SUFFakMsc0JBQXNCO0lBQ2IsUUFBUSxDQUF5QjtJQUUxQyxxQ0FBcUM7SUFDNUIsS0FBSyxDQUFTO0lBRXZCLDJCQUEyQjtJQUNsQixZQUFZLENBQVM7SUFFOUIsOEJBQThCO0lBQ3JCLGtCQUFrQixDQUF5QjtJQUVwRCw0QkFBNEI7SUFDbkIsZ0JBQWdCLENBQXlCO0lBRWxELHdCQUF3QjtJQUV4Qix5QkFBeUI7SUFDaEIsV0FBVyxDQUFTO0lBRTdCLDhCQUE4QjtJQUNyQixPQUFPLENBQVM7SUFFekIsMEJBQTBCO0lBQ2pCLGVBQWUsQ0FBUztJQUVqQywyQkFBMkI7SUFDbEIsZ0JBQWdCLENBQVM7SUFFbEMsdUJBQXVCO0lBQ2QsWUFBWSxDQUFTO0lBRzlCLHNCQUFzQjtJQUV0QixjQUFjO0lBQ0wsVUFBVSxDQUF1QjtJQUUxQyw0QkFBNEI7SUFDbkIsV0FBVyxDQUFVO0lBRTlCLGtDQUFrQztJQUNmLFNBQVMs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