如何在FabricJs画布上的不同地图之间绘制线条动画

时间:2019-08-06 14:01:24

标签: javascript fabricjs

我有两张地图,其中地图1有5个点,地图2有4个点,并且地图上的每个点都由点连接。这是代码段

const canvas = new fabric.Canvas('gameCanvas', {selection: false});

let circles_map1 = [];
let circles_map2 = [];
let lines_map1 = [];
let lines_map2 = [];
let playBack = {
    circles: [],
    lines: []
};

fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';

document.addEventListener('DOMContentLoaded', function()
{
    displayMap(1);
});



document.getElementById('animateBtn').addEventListener('click', function(){
    animateLinesDrawing().then(() => {

        //..clear the playBack
        playBack.circles = [];
        playBack.lines = [];
        displayMap(2);
        animateLinesDrawing().then(() => {
            console.log('animation finished');
        });
    });
});

function displayMap(map)
{
    canvas.clear();
    makeCircles_map(map);
    makeLinesByMap(map);
    
}



function makeCircle(x, y)
{
    return new fabric.Circle({
        left: x,
        top: y,
        strokeWidth: 2,
        radius: 10,
        fill: 'white',
        stroke: '#666',
        selectable: false,
        hoverCursor: 'default',
        hasControls: false,
        hasBorders: false
    });

}

function makeCircles_map(map)
{
    if(map === 1)
    {
        displayLabelText(1);

        //5 circles for map 1
        for(let i = 1; i <= 5; i++)
        {
            const randX = Math.floor((Math.random() * 360) + 30); //between 10 and 400
            const randY = Math.floor((Math.random() * 190) + 10); //between 10 and 200
            const circle = makeCircle(randX, randY);
            playBack.circles.push(circle);
            circles_map1.push(circle);
        }
    }
    else if(map === 2)
    {
       
        displayLabelText(2);

        //4 circles for map 2
        for(let i = 1; i <= 4; i++)
        {
            const randX = Math.floor((Math.random() * 390) + 10); //between 10 and 400
            const randY = Math.floor((Math.random() * 190) + 10); //between 10 and 200
            const circle = makeCircle(randX, randY);
            playBack.circles.push(circle);
            circles_map2.push(circle);  
            
        }
    }
    

}

function displayLabelText(map)
{
     //..label text for the map number
     canvas.add(new fabric.Text('MAP ' + map.toString(), {
        left: 460,
        top: 280,
        fontFamily: 'Arial',
        fontWeight: 'bold',
        fontSize: 20,
        fill: 'black',
        originX: 'center',
        originY: 'center'
   }));
}

function makeLinesByMap(map)
{
    if(map === 1)
    {
        for(i = 0; i < circles_map1.length - 1; i++)
        {
            const circle1 = circles_map1[i];
            const circle2 = circles_map1[i + 1];
            const line = makeLine([circle1.left, circle1.top, circle2.left, circle2.top]);
            playBack.lines.push(line);
            canvas.add(line);

            //..Add the circle and text to the map1(canvas)
            canvas.add(circle1);
            canvas.add(new fabric.Text((i + 1).toString(), {
                left: circle1.left,
                top: circle1.top,
                fontFamily: 'Arial',
                fontWeight: 'bold',
                fontSize: 14,
                fill: 'black',
                originX: 'center',
                originY: 'center'
           }));

           canvas.add(circle2);
           canvas.add(new fabric.Text((i + 2).toString(), {
               left: circle2.left,
               top: circle2.top,
               fontFamily: 'Arial',
               fontWeight: 'bold',
               fontSize: 14,
               fill: 'black',
               originX: 'center',
               originY: 'center'
          }));
        }
        canvas.backgroundColor="gray";
        canvas.renderAll();
    }
    else if(map === 2)
    {
        for(i = 0; i < circles_map2.length - 1; i++)
        {
            const circle1 = circles_map2[i];
            const circle2 = circles_map2[i + 1];
            const line = makeLine([circle1.left, circle1.top, circle2.left, circle2.top]);
            playBack.lines.push(line);
            canvas.add(line);

            //..Add the circle and text to the map1(canvas)
            canvas.add(circle1);
            canvas.add(new fabric.Text((i + 6).toString(), {
                left: circle1.left,
                top: circle1.top,
                fontFamily: 'Arial',
                fontWeight: 'bold',
                fontSize: 14,
                fill: 'black',
                originX: 'center',
                originY: 'center'
           }));

           canvas.add(circle2);
           canvas.add(new fabric.Text((i + 7).toString(), {
               left: circle2.left,
               top: circle2.top,
               fontFamily: 'Arial',
               fontWeight: 'bold',
               fontSize: 14,
               fill: 'black',
               originX: 'center',
               originY: 'center'
          }));
        }

        canvas.backgroundColor="orange";
        canvas.renderAll();
    }
    
}

function makeLine(coords)
{
    return new fabric.Line(coords, {
            fill: 'red',
            stroke: 'red',
            strokeWidth: 4,
            originX: 'right',
            originY: 'center',
            selectable: false,
            hoverCursor: 'default'
    });
}

async function animateLinesDrawing()
{
    
    setLinesCoords();

    for(let i = 0; i < playBack.lines.length; i++)
    {
        await makeAnimation(playBack.lines[i], playBack.circles[i + 1]);
    }

}

function setLinesCoords()
{
    for(let i = 0; i < playBack.lines.length; i++)
    {
        playBack.lines[i].set({
            x1: playBack.circles[i].left,
            y1: playBack.circles[i].top,
            x2: playBack.circles[i].left,
            y2: playBack.circles[i].top
        })
    }
}

function makeAnimation(line, circle)
{
    return new Promise(resolve => {
        line.animate({
            x2: circle.left,
            y2: circle.top
        }, 
        {
            duration: 2000,
            onChange: canvas.renderAll.bind(canvas),
            onComplete: function(){
                line.setCoords();
                //line.setCoords.bind(line);
                resolve();
            }
        });
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
<canvas id="gameCanvas" width="500" height="300" style="border: 2px solid green;"></canvas>
<button id="animateBtn">Animate Lines Drawing</button>

我的问题在动画按钮的事件处理程序内,简而言之,当地图#1的动画结束时,我会显示地图#2,并再次在同一函数内调用动画函数我做递归效率低下。我如何以有效的方式进行递归,这样当我有多个映射时,我应该只调用一个函数,其余函数呢? 感谢您的帮助

0 个答案:

没有答案