我的 JavaScript 画布地图脚本和性能不佳
My javascript canvas map script and poor performance
基本上下面是我的原型脚本,它使用 128x128 图块在画布上绘制地图,用户可以拖动该地图四处移动。
脚本确实有效。但是,我有几个问题需要解决:1.表现不佳,我不知道为什么。2.我缺少在实际绘制之前缓冲瓷砖的方法。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();
为了获得更好的性能,您应该避免更改img
节点的src
,而是移动它们。
最小化处理和修改的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
请求只会更新现有img
标签的x
和y
坐标,而不会更改任何其他内容。同时,屏幕上不会出现的映像节点不超过MAXCACHE
个。
您可以在 中看到完整的工作示例
http://raksy.dyndns.org/tiles/tiles.html
- <脚本类型=“;模块“>负载性能
- 性能:动态脚本注入与服务器渲染脚本
- Ajax发布到PHP脚本,每5秒查询一次MySQL数据库的性能/问题
- 不要为机器人(谷歌和其他)加载JS脚本以获得更好的性能
- 如何优化 jquery 脚本以提高性能
- 压缩脚本和样式,并将所有js和样式引用合并为单个引用,以优化网站性能
- Javascript性能 - 如何提高小脚本的性能
- 无论如何,优化此视差脚本以获得更好的性能
- 谷歌脚本性能下降
- 性能方面:拥有许多小型 ajax php 控制器脚本还是一个大型脚本更好
- Javascript性能-使用$.getScript()添加脚本
- 获取跨域脚本标记的HTML5性能对象
- javascript(jquery)脚本的性能是同步的还是异步的
- 我的 JavaScript 画布地图脚本和性能不佳
- 如何提高搜索脚本的性能
- Jquery数据表fnfilter +脚本性能
- Javascript Rhino + JQuery简单脚本性能问题
- 脚本性能-脚本使浏览器崩溃
- 选项卡失去焦点时的用户脚本性能
- 增强php脚本性能