Search code examples
javascriptangulartypescripthtml5-canvas

Angular - Canvas not redrawing shapes on resizing it


I have an Angular application where I use canvas that I can resize based on the user selection. Now, when I resize my canvas size in the form, the canvas correctly changes size but everything on it disappears, I understand that the canvas clears itself. But then I call a method called redraw which tries to draw those shapes in the canvas again, but it does not.

When I change a coordinates for a element in the canvas, here also I call that redraw method and all shapes again reappears. Can someone please help me resole this issue.

Here is video showing the issue.

enter image description here

ngOnInit(): void {
        console.log('ngOnInit');
        const canvas: HTMLCanvasElement = this.myCanvas.nativeElement;
        this.context = canvas.getContext('2d');
        this.form = this.formBuilder.group({
            labelName: ['', Validators.required],
            labelOrientation: ['VERTICAL', Validators.required],
            labelWidth: [, Validators.required],
            labelHeight: [, Validators.required],
            barcodeLeft: [, Validators.required],
            barcodeTop: [, Validators.required],
            barcodeWidth: [,],
            barcodeHeight: [,],
            gtinLeft: [, Validators.required],
            gtinTop: [, Validators.required],
            gtinWidth: [,],
            gtinHeight: [,],
        });

        this.form.setValue(this.verticalOrientationData);
        this.objSerialLabelDesignModel = this.form.value;
        if (this.context) {
            console.log('ngOnInit check this.context', this.context);
            this.redrawLabel(this.objSerialLabelDesignModel);
        }
        this.onChanges();
    }

    ngAfterViewInit() {
        console.log('ngAfterViewInit');
        this.startDrawing(this.shapesToDrawArray);
    }

    onChanges(): void {
        console.log('onChange!!!!!!');
        // Subscribe to changes in the form value to redraw the label when it changes
        this.form.valueChanges.subscribe((newVal) => {
            this.objSerialLabelDesignModel = newVal;
            this.redrawLabel(this.objSerialLabelDesignModel);
        });
    }

    redrawLabel(result: ISerialLabelDesign) {
        console.log('inside redrawLabel');    
        this.clearDrawing();
        console.log(this.shapesToDrawArray.length);
        this.shapesToDrawArray.length = 0;
        console.log('result::::::::', result); // giving the entire form.value object
        this.defaultLabelWidth = result.labelWidth * 3.7795; // convert from mm to pixel
        this.defaultLabelHeight = result.labelHeight * 3.7795;            
        this.storeDrawing(result);          
        this.startDrawing(this.shapesToDrawArray);
    }

    startDrawing(shapesToDraw: Shape[]) {
        console.log('inside startDrawing::');
        for (var i = 0; i < shapesToDraw.length; i++) {
            const shape = shapesToDraw[i];
            if (shape.type === 'barcode') {
                this.drawRectangle(this.context, shape.x, shape.y, shape.w, shape.h);
            } else if (shape.type === 'text') {
                this.drawText(this.context, shape);
            }
        }
    }

storeDrawing(result: ISerialLabelDesign) {
    this.saveShapes('barcode', undefined, result.barcodeLeft, result.barcodeTop, result.barcodeWidth, result.barcodeHeight,);
    this.saveShapes('text', 'GTIN:', result.gtinLeft, result.gtinTop, 0, 0, result.labelOrientation);
    this.saveShapes('text', 'UID:', result.uidLeft, result.uidTop, 0, 0, result.labelOrientation);
    this.saveShapes('text', 'EXP:', result.expLeft, result.expTop, 0, 0, result.labelOrientation);
    this.saveShapes('text', 'LOT:', result.lotLeft, result.lotTop, 0, 0, result.labelOrientation);
    this.saveShapes('text', 'C PRICE:', result.costpriceLeft, result.costpriceTop, 0, 0, result.labelOrientation);
    this.saveShapes('text', 'S PRICE:', result.sellingpriceLeft, result.sellingpriceTop, 0, 0, result.labelOrientation);
    this.saveShapes('text', '12345678901234', result.gtinWidth, result.gtinHeight, 0, 0, result.labelOrientation);
    this.saveShapes('text', '12345678901234567890', result.uidWidth, result.uidHeight, 0, 0, result.labelOrientation);
    this.saveShapes('text', '2022-01-01', result.expWidth, result.expHeight, 0, 0, result.labelOrientation);
    this.saveShapes('text', '313', result.lotWidth, result.lotHeight, 0, 0, result.labelOrientation);
    this.saveShapes('text', '250000', result.costpriceWidth, result.costpriceHeight, 0, 0, result.labelOrientation);
    this.saveShapes('text', '550000', result.sellingpriceWidth, result.sellingpriceHeight, 0, 0, result.labelOrientation);
}

saveShapes(type: string, text: string | undefined, x: number, y: number, w: number, h: number, orientation?: string) {
    //console.log('length before push:::',this.shapesToDrawArray.length);
    this.createdShapeObject = {
        type: type,
        text: text,
        x: x * 3.7795,
        y: y * 3.7795,
        w: w * 3.7795,
        h: h * 3.7795,
        orientation: orientation
    };
    this.shapesToDrawArray.push(this.createdShapeObject);
    // Show coordinates based on the text position
    let xCoord = x, yCoord = y;
    if (text && orientation === 'VERTICAL') {
        xCoord += h;
    } else {
        yCoord += h;
    }
    console.log(`(${xCoord}, ${yCoord})`);
}

private drawRectangle(context: CanvasRenderingContext2D, x: number, y: number, w: number, h: number) {
    console.log('inside drawRectangle');
    context.strokeRect(x, y, w, h);
}

private drawText(context: CanvasRenderingContext2D, shape: Shape) {
    console.log('inside drawText', shape)
    context.fillStyle = 'black';
    context.font = '8px Arial';
    console.log('shape.orientation', shape.orientation);
    if (shape.orientation === 'HORIZONTAL') {
        console.log('inside HORIZONTAL shape.orientation', shape.orientation);
        this.drawTextHorizontal(context, shape.text, shape.x, shape.y, shape.w, shape.h);
    } else {
        console.log('inside VERTICAL shape.orientation', shape.orientation);
        this.drawTextVertical(context, shape.text, shape.x, shape.y, shape.w, shape.h);
    }
}

Solution

  • Ok for those who come across this issue, the solution is to put the reDraw method in a setTimeout. The reason being the browser renders everything so fast that it does not get the time to draw the shapes once the canvas is cleared.

    setTimeout(() => {         
            this.startDrawing(this.shapesToDrawArray);
        }, 500);