【问题标题】:Canvas scalable arc position画布可缩放弧位
【发布时间】:2012-11-30 10:57:41
【问题描述】:

http://jsfiddle.net/cs5Sg/11/

我想做可伸缩的画布。我创建了两个圆(弧)和一条线,当您单击圆并移动它时,该线将跟随并改变位置。问题是当我添加调整大小的代码时:

var canvas = document.getElementById('myCanvas'),
    context = canvas.getContext('2d'),
    radius = 12,
    p = null,
    point = {
        p1: { x:100, y:250 },
        p2: { x:400, y:100 }
    },
    moving = false;

window.addEventListener("resize", OnResizeCalled, false);

function OnResizeCalled() {
    var gameWidth = window.innerWidth;
    var gameHeight = window.innerHeight;
    var scaleToFitX = gameWidth / 800;
    var scaleToFitY = gameHeight / 480;

    var currentScreenRatio = gameWidth / gameHeight;
    var optimalRatio = Math.min(scaleToFitX, scaleToFitY);

    if (currentScreenRatio >= 1.77 && currentScreenRatio <= 1.79) {
        canvas.style.width = gameWidth + "px";
        canvas.style.height = gameHeight + "px";
    }
    else {
        canvas.style.width = 800 * optimalRatio + "px";
        canvas.style.height = 480 * optimalRatio + "px";
    }
}

function init() {
        return setInterval(draw, 10);
}

canvas.addEventListener('mousedown', function(e) {
    for (p in point) {
        var
            mouseX = e.clientX - 1,
            mouseY = e.clientY - 1,
            distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));

        if (distance <= radius) {
            moving = p;
            break;
        }
    }
});

canvas.addEventListener('mouseup', function(e) {
    moving = false;
});

canvas.addEventListener('mousemove', function(e) {

    if(moving) {
        point[moving].x = e.clientX - 1; 
        point[moving].y = e.clientY - 1;
    }
});


function draw() {
    context.clearRect(0, 0, canvas.width, canvas.height);

    context.beginPath();
    context.moveTo(point.p1.x,point.p1.y);
    context.lineTo(point.p2.x,point.p2.y);

    context.closePath();

    context.fillStyle = '#8ED6FF';
    context.fill();
    context.stroke();

    for (p in point) {
        context.beginPath();
        context.arc(point[p].x,point[p].y,radius,0,2*Math.PI);
        context.fillStyle = 'red';
        context.fill();
        context.stroke();
    }
    context.closePath();
}

init();

画布是可伸缩的,但问题在于点(圆)。当您更改窗口大小时,它们在画布区域上的位置仍然相同,但 distance 更改(因此单击选项失败)。如何解决?

【问题讨论】:

    标签: javascript html animation canvas


    【解决方案1】:

    Live Demo

    基本上你只需要一个考虑到画布实际尺寸的缩放器值,以及像这样的 css 尺寸

    var scaledX = canvas.width/ canvas.offsetWidth,
        scaledY = canvas.height/ canvas.offsetHeight;
    

    然后每次调整窗口大小时,您都需要确保更新缩放器值。

    function OnResizeCalled() {
    
        scaledX = canvas.width/ canvas.offsetWidth;
        scaledY = canvas.height/ canvas.offsetHeight;
    }
    

    要获得正确的坐标,您需要在所有鼠标事件中将 clientXclientY 乘以缩放器

    canvas.addEventListener('mousedown', function(e) {
        for (p in point) {
            var 
                mouseX = e.clientX*scaledX,
                mouseY = e.clientY*scaledY,
                distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));
    
            if (distance <= radius) {
                moving = p;
                break;
            }
        }
    });
    
    
    canvas.addEventListener('mousemove', function(e) {
        var mouseX = e.clientX*scaledX,
            mouseY = e.clientY*scaledY;
    
        if(moving) {
            point[moving].x = mouseX;
            point[moving].y = mouseY;
        }
    });
    

    完整代码

    var canvas = document.getElementById('myCanvas'),
        context = canvas.getContext('2d'),
        radius = 12,
        p = null,
        point = {
            p1: { x:100, y:250},
            p2: { x:400, y:100}
        },
        moving = false,
        scaledX = canvas.width/ canvas.offsetWidth,
        scaledY = canvas.height/ canvas.offsetHeight;
    
    window.addEventListener("resize", OnResizeCalled, false);
    
    function OnResizeCalled() {
        var gameWidth = window.innerWidth;
        var gameHeight = window.innerHeight;
        var scaleToFitX = gameWidth / 800;
        var scaleToFitY = gameHeight / 480;
    
        var currentScreenRatio = gameWidth / gameHeight;
        var optimalRatio = Math.min(scaleToFitX, scaleToFitY);
    
        if (currentScreenRatio >= 1.77 && currentScreenRatio <= 1.79) {
            canvas.style.width = gameWidth + "px";
            canvas.style.height = gameHeight + "px";
        }
        else {
            canvas.style.width = 800 * optimalRatio + "px";
            canvas.style.height = 480 * optimalRatio + "px";
        }
    
        scaledX = canvas.width/ canvas.offsetWidth;
        scaledY = canvas.height/ canvas.offsetHeight;
    }
    
    function init() {
            return setInterval(draw, 10);
    }
    
    canvas.addEventListener('mousedown', function(e) {
        for (p in point) {
            var 
                mouseX = e.clientX*scaledX,
                mouseY = e.clientY*scaledY,
                distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));
    
            if (distance <= radius) {
                moving = p;
                break;
            }
        }
    });
    
    canvas.addEventListener('mouseup', function(e) {
        moving = false;
    });
    
    canvas.addEventListener('mousemove', function(e) {
        var mouseX = e.clientX*scaledX,
            mouseY = e.clientY*scaledY;
    
        if(moving) {
            point[moving].x = mouseX; //1 is the border of your canvas
            point[moving].y = mouseY;
        }
    });
    
    
    function draw() {
        context.clearRect(0, 0, canvas.width, canvas.height);
    
        context.beginPath();
        context.moveTo(point.p1.x,point.p1.y);
        context.lineTo(point.p2.x,point.p2.y);
    
        context.closePath();
    
        context.fillStyle = '#8ED6FF';
        context.fill();
        context.stroke();
    
        for (p in point) {
            context.beginPath();
            context.arc(point[p].x,point[p].y,radius,0,2*Math.PI);
            context.fillStyle = 'red';
            context.fill();
            context.stroke();
        }
        context.closePath();
    }
    
    init();
    

    【讨论】:

    • 我能问点什么吗? :) 为什么在 if 语句中使用 break?它是可选的还是提供更好的效果(加速或其他)?
    • @Amay 它会将其从循环中断开,因此如果距离小于半径,它会找到该点并且不再需要检查。对于少量点,它不需要,但如果您检查 1,000 或更多点,它会给您带来性能提升。
    猜你喜欢
    • 2011-06-22
    • 1970-01-01
    • 2018-04-04
    • 2011-12-28
    • 1970-01-01
    • 2014-08-18
    • 2014-04-16
    • 1970-01-01
    • 2013-10-28
    相关资源
    最近更新 更多