【问题标题】:HTML5 Canvas Viewport for Web Application用于 Web 应用程序的 HTML5 画布视口
【发布时间】:2014-09-18 19:40:20
【问题描述】:

这几天我一直在努力解决这个问题,但无法从类似的问题中解决问题。

有 2 个画布、一个显示较大背景一部分的缩放视口和一个缩小的相机地图。单击第二个画布时,视口应移动到背景的该区域。

var onClick,
onLoad = function () {
    var canvas,
        viewport,
        context,
        canvasWidth,
        canvasHeight,
        viewportContext,
        background = {},
        camera,
        scale = 4;

    function init() {
        background.image = new Image();
        background.image.src = "http://upload.wikimedia.org/wikipedia/commons/4/4e/Coronation_of_Ahmad_Shah_Durrani_in_1747_by_Breshna.jpg";
        canvas = document.getElementById("canvas");
        context = canvas.getContext("2d");
        viewport = document.getElementById("viewport");
        viewportContext = viewport.getContext("2d");
        camera = {
            x: canvas.width/2,
            y: canvas.height/2,
            width: canvas.width/scale,
            height: canvas.height/scale
        };
        background.width = canvas.width * scale;
        background.height = canvas.height * scale;
       
    };
	
  	// Translate viewport's context to camera pos
    function moveContext() {
        viewportContext.setTransform(1, 0, 0, 1, 0, 0); // Reset context
        viewportContext.translate(camera.x*scale, camera.y*scale);
    };
	
  	// Update camera's position
    function moveCamera(vector) {
        camera.x = vector.x;
        camera.y = vector.y;
        moveContext();
    };

    function draw() {
        context.drawImage(background.image, 0, 0, canvas.width, canvas.height);
      // Draw camera guide
        context.strokeStyle = 'red';
        context.beginPath();
        context.moveTo(camera.x - camera.width / 2, camera.y - camera.height / 2);
        context.lineTo(camera.x + camera.width / 2, camera.y - camera.height / 2);
        context.lineTo(camera.x + camera.width / 2, camera.y + camera.height / 2);
        context.lineTo(camera.x - camera.width / 2, camera.y + camera.height / 2);
        context.lineTo(camera.x - camera.width / 2, camera.y - camera.height / 2);
        context.stroke();
		
      	// Draw viewport background
        viewportContext.clearRect(0, 0, viewport.width, viewport.height);
        viewportContext.drawImage(background.image, -background.width/2, -background.height/2, background.width, background.height);
    };

    function update() {
    };

    function gameLoop() {
        update();
        draw();
        requestAnimationFrame(gameLoop);
    };


    onClick = function (event) {
        var x = event.offsetX,
            y = event.offsetY;

        //alert("x: " + x + "\ny: " + y);
        moveCamera({ x: x, y: y });
    };


    init();
    requestAnimationFrame(gameLoop);

    
};

if (window.addEventListener) {
    window.addEventListener("load", onLoad, false);
    window.addEventListener("click", function () { onClick(event) }, false);
}
canvas {
  display:block;
  margin:15px;
  border:1px solid #000;
}
<canvas id="viewport" width="400" height="240">HTML5 Canvas not supported!</canvas>
<canvas id="canvas" width="400" height="240"></canvas>

目前我正在获取鼠标点击的坐标,将相机设置到该位置,重置视口的变换矩阵,然后将视口的上下文转换为相机位置。

显然,我缺少该理论的一个基本部分。

我错过了什么?

【问题讨论】:

  • 你的变换是错误的,它们被颠倒了并且有一个半角偏移。

标签: javascript html canvas


【解决方案1】:

您需要修改您的转换,就像我在评论中所说的那样。试试这个:

    function moveContext() {
        viewportContext.setTransform(1, 0, 0, 1, 0, 0); // Reset context
        viewportContext.translate(
            (viewport.width/2-camera.x+camera.width/2)*scale,
            (viewport.height/2-camera.y+camera.height/2)*scale
        );
    };

整件事:

var onClick,
onLoad = function () {
    var canvas,
        viewport,
        context,
        canvasWidth,
        canvasHeight,
        viewportContext,
        background = {},
        camera,
        scale = 4;

    function init() {
        background.image = new Image();
        background.image.src = "http://upload.wikimedia.org/wikipedia/commons/4/4e/Coronation_of_Ahmad_Shah_Durrani_in_1747_by_Breshna.jpg";
        canvas = document.getElementById("canvas");
        context = canvas.getContext("2d");
        viewport = document.getElementById("viewport");
        viewportContext = viewport.getContext("2d");
        camera = {
            x: canvas.width/2,
            y: canvas.height/2,
            width: canvas.width/scale,
            height: canvas.height/scale
        };
        background.width = canvas.width * scale;
        background.height = canvas.height * scale;
       
    };
	
  	// Translate viewport's context to camera pos
    function moveContext() {
        viewportContext.setTransform(1, 0, 0, 1, 0, 0); // Reset context
        viewportContext.translate(
            (viewport.width/2-camera.x+camera.width/2)*scale,
            (viewport.height/2-camera.y+camera.height/2)*scale
        );
    };
	
  	// Update camera's position
    function moveCamera(vector) {
        camera.x = vector.x;
        camera.y = vector.y;
        moveContext();
    };

    function draw() {
        context.drawImage(background.image, 0, 0, canvas.width, canvas.height);
      // Draw camera guide
        context.strokeStyle = 'red';
        context.beginPath();
        context.moveTo(camera.x - camera.width / 2, camera.y - camera.height / 2);
        context.lineTo(camera.x + camera.width / 2, camera.y - camera.height / 2);
        context.lineTo(camera.x + camera.width / 2, camera.y + camera.height / 2);
        context.lineTo(camera.x - camera.width / 2, camera.y + camera.height / 2);
        context.lineTo(camera.x - camera.width / 2, camera.y - camera.height / 2);
        context.stroke();
		
      	// Draw viewport background
        viewportContext.clearRect(0, 0, viewport.width, viewport.height);
        viewportContext.drawImage(background.image, -background.width/2, -background.height/2, background.width, background.height);
    };

    function update() {
    };

    function gameLoop() {
        update();
        draw();
        requestAnimationFrame(gameLoop);
    };


    onClick = function (event) {
        var x = event.offsetX,
            y = event.offsetY;

        //alert("x: " + x + "\ny: " + y);
        moveCamera({ x: x, y: y });
    };


    init();
    requestAnimationFrame(gameLoop);

    
};

if (window.addEventListener) {
    window.addEventListener("load", onLoad, false);
    window.addEventListener("click", function () { onClick(event) }, false);
}
canvas {
  display:block;
  margin:15px;
  border:1px solid #000;
}
<canvas id="viewport" width="400" height="240">HTML5 Canvas not supported!</canvas>
<canvas id="canvas" width="400" height="240"></canvas>

【讨论】:

  • 您能否详细说明新转换背后的原因?为什么要从视口中心减去相机位置?
  • 这是几次反复试验。添加了视口的中心,因为您已经使用一半来渲染中心的视口,因此是负偏移。相机宽/高偏移是为了补偿红框(Camera)的大小。
  • 通常,当你在做这样的事情时,最好检查在边缘情况下会发生什么,所以所有四个角都是我开始的。
猜你喜欢
  • 2011-05-15
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 2013-05-05
  • 2011-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多