Manuel Brás
Manuel Brás

Reputation: 513

Angular - HTML Canvas turns black when I start drawing

I'm building an Angular app where I intend to let the user draw text fields over PDF pages. For this, I'm using ng2-pdf-viewer library and I have a PDF page component that will hold a PDF page, as well as its corresponding HTML canvas element.

The problem I'm facing is that the canvas turns black when I start drawing on the respective PDF page. Although I am able to draw successfully, this means the whole page background turns to black.

Here is how it looks (the PDF page with content is behind that black background):

enter image description here

My page component code is the following:

export class PdfPreviewPageComponent {
    @Input() pdfSrc: string = '';
    @Input() pdfPageNumber!: number;

    @ViewChild('pdfViewer', { static: false, read: ElementRef }) pdfViewerRef!: ElementRef;

    private canvas!: HTMLCanvasElement;
    private cx: CanvasRenderingContext2D | null = null;
    private isDrawing: boolean = false;
    private startX!: number;
    private startY!: number;

    // UPDATE: changed from getting the canvas via input and using ngOnChanges to
    // using the (page-rendered) event provided by ng2-pdf-viewer library
    onPageLoaded(event: Event) {
        if (!this.canvas) {
            this.canvas = this._document.getElementsByTagName('canvas')[this.pdfPageNumber - 1];
            this.ctx = this.canvas.getContext('2d');

            if (this.ctx) {
                this.ctx.fillStyle = 'red';
                this.ctx.lineWidth = 2;
                this.handleCanvasEvent();
            }
        }
    }

    private handleCanvasEvent() {
        this.canvas.addEventListener('mousemove', (event) => this.onMouseMove(event));
        this.canvas.addEventListener('mousedown', (event) => this.onMouseDown(event));
        this.canvas.addEventListener('mouseup', (event) => this.onMouseUp(event));
    }

    private onMouseDown(event: MouseEvent) {
        this.isDrawing = true;
        this.startX = event.clientX - this.canvas.getBoundingClientRect().left;
        this.startY = event.clientY - this.canvas.getBoundingClientRect().top;
    }

    private onMouseMove(event: MouseEvent) {
        if (!this.isDrawing) {
            return;
        }

        const currentX = event.clientX - this.canvas.getBoundingClientRect().left;
        const currentY = event.clientY - this.canvas.getBoundingClientRect().top;
        const width = currentX - this.startX;
        const height = currentY - this.startY;

        this.clearCanvas();
        this.drawRectangle(this.startX, this.startY, width, height);
    }

    private onMouseUp(event: MouseEvent) {
        this.isDrawing = false;
    }

    private clearCanvas() {
        if (this.cx) {
            this.cx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        }
    }

    private drawRectangle(x: number, y: number, width: number, height: number) {
        if (this.cx) {
            this.cx.strokeRect(x, y, width, height);
        }
    }
    ...
    ...
}

How can I avoid the canvas turning completely black? I don't want to hide the content of the PDF page as the whole purpose is for the user to draw text fields (rectangles) where they may see fit.

Here is the stackblitz project.

Upvotes: 0

Views: 375

Answers (1)

Manuel Brás
Manuel Brás

Reputation: 513

The problem is that I was trying to use and manipulate the canvas that the ng2-pdf-viewer library uses on each of its PDF viewer elements. This is the canvas that renders the PDF content, so once you call any canvas clearing methods (such as clearRect()) on this canvas, you will inevitably delete all of the PDF page content.

The correct approach is to create your own canvas elements and overlay them on top of their respective pages, using absolute or relative positioning and making sure each canvas is on top of the stacking order with z-index.

Upvotes: 0

Related Questions