我的javascript画布地图脚本和性能不佳

时间:2014-08-17 06:48:29

标签: javascript canvas

基本上下面是我的原型脚本,它使用128x128磁贴在画布上绘制地图,用户可以拖动它来移动。

脚本确实有用。但是我有一些问题需要解决: 1.表现不佳,我无法弄清楚原因。 我错过了在实际绘图之前缓冲瓷砖的方法。 3.如果你发现任何其他问题也可以帮助我让事情变得更顺利,那就太棒了。

脚本的一些解释:

变量

坐标 - 定义要显示的实际图像。图像文件名是' 0_1.jpg'的类型,其中0是Y,1是X.

mouse_position - 顾名思义,就是记录鼠标位置。

position - 这是一个命名不佳的变量。它定义了在画布上绘制的上下文的位置。当用户拖动视图时,这会发生变化。


任何帮助都将受到极大的赞赏。谢谢。

var coordinates = [0, 0];
var mouse_position = [0, 0];
var position = [-128, -128];

var canvas = document.getElementById('map_canvas');
var context = canvas.getContext('2d');

var buffer = [];
var buffer_x = Math.floor(window.innerWidth/128)+4;
var buffer_y = Math.floor(window.innerHeight/128)+4;


var animation_frame_request = function() {
    var a = window.requestAnimationFrame;
    var b = window.webkitRequestAnimationFrame;
    var c = window.mozRequestAnimationFrame;
    var d = function(callback) {
        window.setTimeout(callback, 1000/60);
    }

    return a || b || c || d;
}





var resizeCanvas = function() {
    window.canvas.width = window.innerWidth;
    window.canvas.height = window.innerHeight;


    window.buffer_x = Math.floor(window.innerWidth/128)+4;
    window.buffer_y = Math.floor(window.innerHeight/128)+4;


    window.buffer = [];

    for (row = 0; row < window.buffer_y; row++) {
        x = [];
        for (col = 0; col < window.buffer_x; col++) {
            x.push(new Image());
        }

        window.buffer.push(x);
    }
}




var render = function() {
    animation_frame_request(render);

    for (row = 0; row < window.buffer_y; row++) {
        for (col = 0; col < window.buffer_x; col++) {
            cy = window.coordinates[1]+row;
            cx = window.coordinates[0]+col;
            window.buffer[row][col].src =  'map/'+cy+'_'+cx+'.jpg';
        }
    }

    for (row = 0; row < window.buffer_y; row++) {
        for (col = 0; col < window.buffer_x; col++) {
            window.context.drawImage(window.buffer[row][col],
                                     window.position[0]+col*128,
                                     window.position[1]+row*128, 128, 128);
        }
    }
}




var events = function() {

    window.canvas.onmousemove = function(e) {

        if (e['buttons'] == 1) {

            window.position[0] += (e.clientX-window.mouse_position[0]);
            window.position[1] += (e.clientY-window.mouse_position[1]);

            if (window.position[0] >= 0) {
                window.position[0] = -128;
                window.coordinates[0] -= 1;
            } else if (window.position[0] < -128) {
                window.position[0] = 0;
                window.coordinates[0] += 1;
            }

            if (window.position[1] >= 0) {
                window.position[1] = -128;
                window.coordinates[1] -= 1;
            } else if (window.position[1] < -128) {
                window.position[1] = 0;
                window.coordinates[1] += 1;
            }

            render();
        }

        window.mouse_position[0] = e.clientX;
        window.mouse_position[1] = e.clientY;
    }
}


window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('load', resizeCanvas, false);
window.addEventListener('mousemove', events, false);

resizeCanvas();

1 个答案:

答案 0 :(得分:2)

为了获得更好的性能,您应该避免更改srcimg节点并将其移动。

最小化处理和修改的img节点数量(屏幕定位除外)的一种简单方法是使用LRU(最近最少使用)缓存。

基本上,您通过使用将src url映射到节点对象的字典并将它们全部保存在双向链接列表中来保留最后说100个图像节点的缓存(它们必须足以覆盖至少一个屏幕)。

当需要磁贴时,首先检查缓存,如果它已经存在,只需将其移动到LRU列表的前面并移动img坐标,否则创建一个新节点并设置源或,如果您已达到缓存限制,请重新使用双向链接列表中的最后一个节点。在代码中:

function setTile(x, y, src) {
    var t = cache[src];
    if (!t) {
        if (cache_count == MAXCACHE) {
            t = lru_last;
            t.prev.next = null;
            lru_last = t.prev;
            t.prev = t.next = null;
            delete cache[t.src]
            t.src = src;
            t.img.src = src;
            cache[t.src] = t;
        } else {
            t = { prev: null,
                  next: null,
                  img: document.createElement("img") };
            t.src = src;
            t.img.src = src;
            t.img.className = "tile";
            scr.appendChild(t.img);
            cache[t.src] = t;
            cache_count += 1;
        }
    } else {
        if (t.prev) t.prev.next = t.next; else lru_first = t.next;
        if (t.next) t.next.prev = t.prev; else lru_last = t.prev;
    }
    t.prev = null; t.next = lru_first;
    if (t.next) t.next.prev = t; else lru_last = t;
    lru_first = t;

    t.img.style.left = x + "px";
    t.img.style.top = y + "px";
    scr.appendChild(t.img);
}

我也总是将请求的图块附加到容器中,以便它位于所有其他现有图块的前面;通过这种方式,我不需要移除旧瓷砖,而只是将它们留在后面。

要更新屏幕,我只需迭代我需要的所有图块并请求它们:

function setView(x0, y0) {
    var w = scr.offsetWidth;
    var h = scr.offsetHeight;
    var iy0 = y0 >> 7;
    var ix0 = x0 >> 7;
    for (var y=iy0; y*128 < y0+h; y++) {
        for (var x=ix0; x*128 < x0+w; x++) {
            setTile(x*128-x0, y*128-y0, "tile_" + y + "_" + x + ".jpg");
        }
    }
}

大多数情况下,setTile请求只会更新现有x代码的yimg坐标,而不会更改任何其他内容。同时,屏幕上不会出现MAXCACHE个图像节点。

您可以在

中看到完整的工作示例

http://raksy.dyndns.org/tiles/tiles.html