HTML5画布,移动后图像闪烁

时间:2019-11-15 12:47:44

标签: javascript html typescript canvas

当我尝试使用以下代码移动图像时(当从typescrpt编译为js时),图像会闪烁。

注意:this.image是在父级中设置的,画布ID和尺寸也是如此。还将图像的起始坐标设置为0、0。

const Tool = require('../tools');

interface Coords {
    x : number;
    y : number;
}

class MoveTool extends Tool {

    button: HTMLElement;
    canvas: HTMLCanvasElement;  
    isDraggable: boolean;

    public constructor(element : MouseEvent) {
        if(!__states.activeLayer) return;
        super(element);
        this.canvasEditMode();
        this.run();
    }    

    private canvasEditMode() : void {
        if(!this.canvas) return;
        this.canvas.style.cursor = 'crosshair';
    }

    public run() : void {
        this.isDraggable = false;
        this.mouseEvents();
    }


    public mouseEvents() {
        this.mouseD = this.mouseDown.bind(this);
        this.mouseM = this.mouseMove.bind(this);
        this.mouseU = this.mouseUp.bind(this);
        this.canvas.addEventListener('mousedown', this.mouseD);
        this.canvas.addEventListener('mousemove', this.mouseM); 
        this.canvas.addEventListener('mouseup', this.mouseU);
    }

    public tick() {
        this.clearCanvas();
        this.context.drawImage(this.image, this.currentX, this.currentY);
        this.requestId = window.requestAnimationFrame(() => this.tick());
    }


    public quit() : void {
        document.getElementById(__states.activeLayer).style.cursor = 'pointer';
        this.canvas.removeEventListener('mousedown', this.mouseD);
        this.canvas.removeEventListener('mousemove', this.mouseM);
        this.canvas.removeEventListener('mouseup', this.mouseU);
    }


    public mouseDown(event : MouseEvent) : void {
        event.preventDefault();
        this.isDraggable = true;
        this.startCur = this.getCursorPosition(event);
    }

    public mouseUp(event : MouseEvent) : void {
        event.preventDefault();
        __states.layer.layers[__states.activeLayer].x = this.currentX;
        __states.layer.layers[__states.activeLayer].y = this.currentY;
        this.isDraggable = false;
        window.cancelAnimationFrame(this.requestId);
    }

    public mouseMove(event: MouseEvent) {
        event.preventDefault();

        if (!this.isDraggable) return;
        this.cursor = this.getCursorPosition(event);
        this.currentX = this.calcCurrent(this.currentX, this.cursor.x, this.coordsDist(this.startCur.x, this.cursor.x)); 
        this.currentY = this.calcCurrent(this.currentY, this.cursor.y, this.coordsDist(this.startCur.y, this.cursor.y));
        this.requestId = window.requestAnimationFrame(() => this.tick());

    }

    // srt : start co-ordinate,  cnt : current co-ordinate
    private coordsDist(srt : number, cnt : number) : number {
        return srt === cnt ? 0 : srt > cnt ? srt - cnt : cnt - srt; 
    }

    // distance between cursor at mousedown and current position
    private calcCurrent(origCoord : number , currentCoord : number, cursorTravel : number) : number {
        return origCoord > currentCoord ? origCoord - cursorTravel : origCoord + cursorTravel;
    }




}

任何解决问题的想法都将受到赞赏,因为我已经在此上浪费了一天,谢谢

1 个答案:

答案 0 :(得分:0)

您将在每个mousemove事件中启动一个新的rAF循环(在最新的浏览器中每帧一个,通常在较旧的浏览器中更多)。
您的浏览器在移动图像时可能难以按每帧绘制呈指数级增长的图像。
cancelAnimationFrame中的mouseUp调用只会停止最后一个创建的调用,但是从mouseDown创建的所有调用仍将无休止地运行。

快速解决方案:在您的cancelAnimationFrame( this.requestId );处理程序中调用mouseMove(在调用下一个this.requestId = requestAnimationFrame(...之前。)
其他解决方案:高举一个标志,让您知道是否已请求新框架。