Skip to content

Instantly share code, notes, and snippets.

@gourytch
Last active July 5, 2016 05:01
Show Gist options
  • Save gourytch/ba7d5939d98c5db0e80da2da70b97323 to your computer and use it in GitHub Desktop.
Save gourytch/ba7d5939d98c5db0e80da2da70b97323 to your computer and use it in GitHub Desktop.
livemap.js, переформатированный для удобочитаемости
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// LIVEMAP_REFORMATTED.JS
// SOURCE: http://map.playrust.io/js/rustio/livemap.js
// FORMAT: http://jsbeautifier.org/
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function initLiveMap() {
$('#signin').click(function() {
var returnUrl = self == top ? document.location.href : document.referrer;
report('SignIn', function() {
window.top.location = "http://" + endpoint + "/signin?return=" + encodeURIComponent(returnUrl);
});
return false;
});
$('#signout').click(function() {
var returnUrl = document.location.href;
report('SignOut', function() {
document.location = "http://" + endpoint + "/signout?return=" + encodeURIComponent(returnUrl);
});
return false;
});
updateMap("http://" + endpoint + "/map.jpg");
$('#connect').prop("href", "steam://connect/" + endpoint);
$('#allieslist, #recentlist').bind("mousewheel DOMMouseScroll", function(e) {
var scrollTo;
if (e.type == 'mousewheel') {
scrollTo = (e.originalEvent.wheelDelta * -1);
} else if (e.type == 'DOMMouseScroll') {
scrollTo = 20 * e.originalEvent.detail;
}
if (scrollTo) {
e.stopPropagation();
e.preventDefault();
$(this).scrollTop(scrollTo + $(this).scrollTop());
return false;
}
});
var $recentFilter = $('#recent-filter');
$recentFilter.bind("change keyup", function(evt) {
var val = $recentFilter.val().toLowerCase();
if (val.length == 0) {
$recentlist.find(".player").show();
return;
}
$recentlist.find(".player").each(function(i, elem) {
var elem = $(elem);
if (elem.text().toLowerCase().indexOf(val) >= 0)
elem.show();
else
elem.hide();
});
});
var consoleWindow = null;
$('#openconsole').click(function(evt) {
if (consoleWindow && !consoleWindow.closed) {
consoleWindow.focus();
} else {
consoleWindow = window.open("http://console.playrust.io/?" + endpoint, "_blank");
consoleWindow.onbeforeunload = function() {
consoleWindow = null;
};
}
evt.preventDefault();
return false;
});
$('#ownertoggle').click(function(evt) {
if (!connect.socket)
return;
connect.socket.send("owner.toggle");
});
$window.bind("beforeunload", function() {
if (consoleWindow)
consoleWindow.close();
});
function start() {
$('#hostname').prop("title", _("Hit F1 in game and type into the console:") + " client.connect " + endpoint);
var signinMessage = _("Log in to locate yourself on the map in real time and to share your location with your friends and allies!");
$('#signin').tooltipster({
position: "bottom",
content: '<div style="padding-bottom: 8px">' + signinMessage + '</div><img src="img/signin-hint.jpg" />',
contentAsHTML: true,
maxWidth: 270,
offsetX: -50,
offsetY: 20,
autoClose: false
});
try {
$('#signin').tooltipster('show');
} catch (err) {}
updateStatus(function() {
setInterval(updateStatus, 60000);
connect();
if (config.displayMonuments)
updateMonuments();
if (config.displayBuildings)
updateBuildings(), setInterval(updateBuildings, 60000 * 30);
if (config.displayMortality)
updateMortality(), setInterval(updateMortality, 60000 * 15);
onResize();
});
}
console.log("loading config ...");
getJSON("http://" + endpoint + "/config.json", function(data) {
config = data || {};
if (typeof config.enableLocationSharing === 'undefined')
config.enableLocationSharing = true;
console.log("config loaded");
if (window.top != window) {
window.top.location = document.location.href;
return;
}
initTheAnnoyingAds();
toggleCss("displayMonuments", !!config.displayMonuments);
toggleCss("displayBuildings", !!config.displayBuildings);
toggleCss("displayMortality", !!config.displayMortality);
toggleCss("displayLoot", false);
onResize();
var lang = $.cookie('lang') || config.defaultLanguage;
if (!lang != "en") {
i18n.load(lang, function(err) {
if (!err) {
$langselect.val(lang);
$('#download-link').tooltipster();
}
start();
});
} else start();
}).fail(function(xhr, err) {
console.log("loading config failed:", err);
alert(_("The server \"{ADDRESS}\" is not responding. Please contact the server's administrator.", {
ADDRESS: endpoint
}));
});
}
function connect() {
if (typeof WebSocket == "undefined") {
alert(_("Sorry, your browser does not support WebSockets. Please consider an upgrade to use RustWeb!"));
return;
}
console.log("connecting to websocket ...");
var socket = connect.socket = new WebSocket("ws://" + endpoint + "/ms");
socket.onopen = function() {
console.log("connected to websocket");
}
socket.onmessage = function(e) {
var msg = e.data,
cmd, data;
var p = msg.indexOf(" ");
if (p < 0) {
cmd = msg;
data = null;
} else {
cmd = msg.substring(0, p);
data = JSON.parse(msg.substring(p + 1));
}
switch (cmd) {
case "hello":
console.log("greeted by server");
socket.send("hello");
break;
case "session":
console.log("received session info: " + data._id);
session = data;
userId = data.id;
toggleCss("signedin", true);
toggleCss("owner", session.owner);
if (!config.enableLocationSharing)
$friends.hide();
else
$friends.show();
try {
$('#signin').tooltipster('hide');
} catch (err) {}
notify(_("{YOU} just signed in", {
"YOU": "<strong>" + _("You") + "</strong>"
}));
updateAllies();
updateRecent();
if (session.owner) {
if (!config.displayBuildings) {
toggleCss("displayBuildings", true);
updateBuildings();
intervals.push(setInterval(updateBuildings, 60000 * 30));
}
if (!config.displayMortality) {
toggleCss("displayMortality", true);
updateMortality();
intervals.push(setInterval(updateMortality, 60000 * 15));
}
toggleCss("displayLoot", true);
updateLoot();
intervals.push(setInterval(updateLoot, 60000 * 10));
onResize();
}
report('SignedIn');
break;
case "friend.add":
if (!config.enableLocationSharing) {
console.log("skipped adding friend as location sharing is disabled");
break;
}
console.log("received added friend: " + data.id);
session.friends.push(data);
updateAllies();
notify(_("{YOU} now share your location with {NAME}", {
"YOU": "<strong>" + _("You") + "</strong>",
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
report('AddFriend');
break;
case "friend.del":
if (!config.enableLocationSharing) {
console.log("skipped deleting friend as location sharing is disabled");
break;
}
console.log("received deleted friend: " + data.id);
for (var i = 0; i < session.friends.length; ++i) {
if (session.friends[i].id == data.id) {
session.friends.splice(i, 1);
updateAllies();
notify(_("{YOU} no longer share your location with {NAME}", {
"YOU": "<strong>" + _("You") + "</strong>",
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
break;
}
}
report('DeleteFriend');
break;
case "share.add":
if (!config.enableLocationSharing) {
console.log("skipped adding share as location sharing is disabled");
break;
}
console.log("received added share: " + data.id);
session.shares.push(data);
updateAllies();
notify(_("{NAME} now shares their location with you", {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
var loc = locations[data.id];
if (loc)
loc.elem.prop("src", "/img/ally.png");
break;
case "share.del":
if (!config.enableLocationSharing) {
console.log("skipped deleting share as location sharing is disabled");
break;
}
console.log("received deleted share: " + data.id);
for (var i = 0; i < session.shares.length; ++i) {
if (session.shares[i].id == data.id) {
session.shares.splice(i, 1);
updateAllies();
var loc = locations[data.id];
if (loc) {
loc.elem.remove();
delete locations[data.id];
}
notify(_("{NAME} no longer shares their location with you", {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
break;
}
}
break;
case "l":
if (!config.enableLocationSharing && !session.owner && data.id != userId) {
console.log("skipped player location as location sharing is disabled");
break;
}
updatePlayerLocation(data, false);
break;
case "s":
if (!config.enableLocationSharing) {
console.log("skipped sleeper location as location sharing is disabled");
break;
}
updatePlayerLocation(data, true);
break;
case "player.connect":
console.log("received player connect: " + data.id);
if (session.owner)
notify(_("{NAME} just woke up", {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
var rec = addRecent(data.id, data.name);
if (rec != null)
$recentlist.prepend(rec.elem.detach());
break;
case "player.disconnect":
console.log("received player disconnect: " + data.id);
if (session.owner)
notify(_("{NAME} fell asleep", {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
var loc = locations[data.id];
if (loc && !loc.dead) {
loc.sleeping = true;
loc.update();
}
break;
case "player.chat":
console.log("received player spawn: " + data.id);
notify(_("{NAME} says:", {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}) + " " + escapeHtml(data.message));
break;
case "player.spawn":
console.log("received player spawn: " + data.id);
notify(_("{NAME} spawned in the middle of nowhere", {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
break;
case "player.death":
console.log("received player death: " + data.id);
notify(_(damageToReason(data.lastDamage), {
"NAME": "<strong>" + escapeHtml(data.name) + "</strong>"
}));
var loc = locations[data.id];
if (loc && loc.sleeping) {
loc.sleeping = false;
loc.dead = true;
loc.update();
}
break;
case "p":
case "h":
updateSpecialLocation(cmd, data);
break;
case "plane.drop":
break;
case "owner.toggle":
if (!data.owner) {
notify(_("{YOU} are now using the map as player", {
"YOU": "<strong>" + _("You") + "</strong>"
}));
var newLocations = {};
for (var i in locations)
if (locations.hasOwnProperty(i) && locations[i].type == "player" && locations[i].id != userId && !isShare(locations[i].id)) {
if (locations[i].elem)
locations[i].elem.remove();
} else
newLocations[i] = locations[i];
locations = newLocations;
} else {
notify(_("{YOU} are now using the map as admin", {
"YOU": "<strong>" + _("You") + "</strong>"
}));
}
break;
case "ping":
console.log("ping");
break;
default:
console.log("received unknown command: " + cmd);
break;
}
}
socket.onclose = function(e) {
console.log("disconnected from websocket (trying to reconnect in 20s)");
setTimeout(function() {
connect();
}, 20000);
toggleCss("signedin", false);
toggleCss("owner", false);
delete connect.socket;
cleanup();
}
socket.onerror = function(e) {
console.log("websocket error: " + e.error);
}
}
function updateStatus(cb) {
console.log("updating status ...");
getJSON("http://" + endpoint + "/status.json", function(data) {
server = data;
server.hostname = server.hostname.substring(0, 63);
$('#hostname').text(server.hostname).tooltipster({
position: "bottom",
interactive: true
});
$('#level').text(_(server.level)).prop("title", _("Worldsize {WORLDSIZE}, Seed {SEED}", {
"WORLDSIZE": server.world.size,
"SEED": server.world.seed
})).tooltipster({
position: "bottom"
});
$('#numplayers').text(_("{NUM} / {MAX} players", {
"NUM": server.players,
"MAX": server.maxplayers
}));
$('#numsleepers').text(_("{NUM} sleepers", {
"NUM": server.sleepers
}));
document.title = server.hostname;
console.log("status updated");
if (cb) cb();
}).fail(function(xhr, err) {
console.log("status update failed: " + err.message);
});
}
function updatePlayerLocation(data, isSleeper) {
var loc, pos = worldToMap(data),
rot = data.r,
player, elem;
if (!locations.hasOwnProperty(data.id)) {
player = findRecent(data.id);
if (!player && typeof data.name === 'string' && data.name != data.id) {
player = addRecent(data.id, data.name);
}
console.log("creating player " + data.id);
$landmarks.append(elem = $('<img class="player" alt="" id="player-' + data.id + '" />'));
elem.prop("title", userId == data.id ? _("This is you!") : player ? player.name : data.id);
elem.prop('src', "img/player.png");
elem.css({
width: iconSize + "px",
left: (pos.x - iconSize / 2) + "px",
top: (pos.y - iconSize / 2) + "px",
transform: "rotate(" + rot + "deg)"
});
elem.tooltipster({
position: "top",
offsetY: -10,
positionTracker: true,
positionTrackerCallback: function() {}
});
elem.bind("mousedown", function(evt) {
evt.stopPropagation();
});
loc = locations[data.id] = {};
loc.type = "player";
loc.id = data.id;
loc.pos = pos;
loc.rot = rot;
loc.elem = elem;
loc.dead = typeof data.d == 'undefined' ? false : !!data.d
loc.sleeping = !!isSleeper;
loc.wasDead = loc.dead;
loc.wasSleeping = loc.sleeping;
loc.update = (function() {
if (this.dead || this.sleeping) {
this.elem.css({
transform: "rotate(0deg)",
zIndex: this.dead ? 101 : 100
});
} else {
this.elem.css({
zIndex: userId == data.id ? 103 : 102
});
}
var img;
if (this.dead) {
img = "img/dead.png";
} else if (this.sleeping) {
img = isShare(this.id) ? "img/sleeper-ally.png" : "img/sleeper.png";
} else if (userId == this.id) {
img = "img/self.png";
} else if (isShare(this.id)) {
img = "img/ally.png";
} else {
img = "img/player.png";
}
if (this.elem.prop("src") != img)
this.elem.prop("src", img);
}).bind(loc);
} else {
loc = locations[data.id];
loc.wasSleeping = loc.sleeping;
loc.sleeping = !!isSleeper;
var duration = 990;
if (typeof data.d === 'number')
loc.dead = !!data.d;
if (loc.wasDead || loc.dead) {
if (loc.wasDead)
loc.wasDead = false;
duration = 0;
}
loc.elem.transition({
"left": (pos.x - iconSize / 2) + "px",
"top": (pos.y - iconSize / 2) + "px"
}, duration, "linear");
loc.elem.css({
"transform": "rotate(" + rot + "deg)"
});
loc.pos = pos;
loc.rot = rot;
}
if (typeof data.d === 'number')
loc.wasDead = !!data.d;
loc.time = Date.now();
loc.update();
}
function updateSpecialLocation(type, data) {
var loc, pos = worldToMap(data),
rot = data.r,
elem;
var key, name, img;
if (type === "p") {
key = "plane";
name = _("Plane");
img = "img/plane.png";
} else {
key = "helicopter";
name = _("Helicopter");
img = "img/heli.gif";
rot += 180;
}
if (!locations.hasOwnProperty(data.id)) {
if (data.k)
return;
if (inBounds(pos)) {
console.log("Creating " + key + ": " + data.id);
$landmarks.append(elem = $('<img class="' + key + '" alt="" id="' + key + '-' + data.id + '" />'));
elem.prop("title", name);
elem.prop("src", img);
elem.css({
width: iconSize + "px",
left: (pos.x - iconSize / 2) + "px",
top: (pos.y - iconSize / 2) + "px",
transform: "rotate(" + rot + "deg)",
zIndex: 200
});
elem.bind("mousedown", function(evt) {
evt.stopPropagation();
});
loc = locations[data.id] = {};
loc.type = key;
loc.id = data.id;
loc.pos = pos;
loc.rot = rot;
loc.time = Date.now();
loc.elem = elem;
}
} else {
loc = locations[data.id];
if (inBounds(pos) && !data.k) {
loc.time = Date.now();
var realRot = rot;
var diff = loc.rot - rot;
if (diff > 180)
rot += 360;
else if (diff < -180)
rot -= 360;
loc.elem.transition({
"left": (pos.x - iconSize / 2) + "px",
"top": (pos.y - iconSize / 2) + "px",
"rotate": rot + "deg"
}, 990, "linear", function() {
loc.elem.css({
"transform": "rotate(" + realRot + "deg)"
});
});
loc.pos = pos;
loc.rot = realRot;
} else {
console.log("Removing " + key + ": " + data.id);
loc.elem.remove();
delete locations[data.id];
}
}
}
function updateMonuments(cb) {
console.log("updating monuments ...");
getJSON("http://" + endpoint + "/monuments.json", function(data) {
updateMonumentsFrom(data);
console.log("monuments updated");
if (cb) cb();
}).fail(function(xhr, err) {
console.log("monuments update failed: " + err.message);
});
}
function updateBuildings(cb) {
console.log("updating buildings ...");
var size = 3.5 * viewportSize / server.world.size,
canvas = document.getElementById("buildings"),
ctx = canvas.getContext("2d");
canvas.width = viewportSize;
canvas.height = viewportSize;
var batch = [];
function process(task) {
if (typeof task !== 'undefined') {
batch.push(task);
if (batch.length < 100)
return;
}
setTimeout(function(batch, last) {
for (var i = 0; i < batch.length; ++i)
batch[i]();
if (last)
console.log("buildings updated");
}.bind(this, batch, typeof task === 'undefined'), 0);
batch = [];
}
getJSON("http://" + endpoint + "/buildings.json", function(data) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
$.each(data, function(i, obj) {
if (obj.name != "foundation")
return;
process(function(obj) {
var pos = worldToMap(obj.position);
ctx.save();
ctx.moveTo(pos.x, pos.y);
ctx.translate(pos.x, pos.y);
ctx.rotate(obj.rotation / 180 * Math.PI);
ctx.fillStyle = "rgba(0,0,0,0.5)";
ctx.fillRect(-size / 2 - 0.5, -size / 2 - 0.5, size + 1, size + 1);
ctx.restore();
}.bind(this, obj));
});
$.each(data, function(i, obj) {
if (obj.name != "foundation")
return;
process(function(obj) {
var pos = worldToMap(obj.position);
ctx.save();
ctx.moveTo(pos.x, pos.y);
ctx.translate(pos.x, pos.y);
ctx.rotate(obj.rotation / 180 * Math.PI);
ctx.fillStyle = "#ae8753";
ctx.fillRect(-size / 2, -size / 2, size, size);
ctx.restore();
}.bind(this, obj));
});
process();
console.log("processing " + data.length + " drawable buildings ...");
if (cb) cb(null);
}).fail(function(xhr, err) {
console.log("buildings update failed: " + err.message);
if (cb) cb(err);
});;
}
var mortalityMap;
function updateMortality() {
if (!mortalityMap) {
mortalityMap = h337.create({
container: document.getElementById("mortality"),
minOpacity: 0.0,
maxOpacity: 0.2,
radius: mortalityRes * 2
});
$mortality.css("position", "absolute");
}
console.log("updating mortality ...");
getJSON("http://" + endpoint + "/deaths.json", function(data) {
var ddata = [],
totals = {},
key;
$.each(data, function(i, death) {
var pos = worldToMap(death),
cellX = (pos.x / mortalityRes) | 0,
cellY = (pos.y / mortalityRes) | 0;
ddata.push({
x: cellX * mortalityRes,
y: cellY * mortalityRes,
value: 1
});
key = cellX + "," + cellY;
if (typeof totals[key] === 'undefined')
totals[key] = 1;
else
totals[key]++;
});
var max = 1;
$.each(totals, function(k, v) {
if (v > max)
max = v;
});
mortalityMap.setData({
max: max,
data: ddata
});
console.log("mortality updated: max=" + max);
}).fail(function(xhr, err) {
console.log("mortality update failed: " + err.message);
});;
}
var itemNames, hotItems = ["explosive.timed", "explosives", "metal.facemask", "metal.plate.torso", "bucket.helmet", "coffeecan.helmet", "rifle.ak", "rifle.bolt", "smg.thompson", "shotgun.pump", "shotgun.waterpipe", "revolver", "smg.2", "pistol.semiauto", "crossbow", "supply.signal", "rocket.launcher"],
hotBlueprints = ["ammo_shotgun", "ammo.shotgun.slug", "ammo_pistol", "ammo.pistol.fire", "ammo.pistol.hv", "ammo_rifle", "ammo.rifle.explosive", "ammo.rifle.incendiary", "ammo.rifle.hv", "ammo.rocket.basic", "ammo.rocket.fire", "ammo.rocket.hv", "ammo.rocket.smoke", "arrow.hv", "grenade.f1", "largemedkit", "hatchet", "axe.salvaged", "pickaxe", "icepick.salvaged", "lock.code", "box.wooden.large", "hat.candle", "hat.miner"];
function updateLoot() {
function update() {
getJSON("http://" + endpoint + "/loot.json", function(data) {
$loot.find(".loot").remove();
$.each(data, function(i, item) {
var inv = [];
var hot = false;
$.each(item.inventory, function(j, iitem) {
if (hotItems.indexOf(iitem.name) >= 0 || (iitem.blueprint && hotBlueprints.indexOf(iitem.name) >= 0))
hot = true;
inv.push((iitem.amount > 1 ? iitem.amount + "x " : "") +
(itemNames && itemNames[iitem.name] ? itemNames[iitem.name] : iitem.name) +
(iitem.blueprint ? " (BP)" : ""));
});
if (inv.length == 0)
inv.push(_("nothing"));
var pos = worldToMap(item.position),
size = iconSize;
$loot.append(elem = $('<img class="loot" alt="" />'));
elem.prop("title", _("Loot") + ": " + inv.join(', '));
if (item.name.indexOf("supply_drop") >= 0) {
elem.prop("src", "img/supply.png");
} else {
elem.prop("src", hot ? "img/barrel-hot.png" : "img/barrel.png");
size = size / 2;
}
elem.css({
width: size + "px",
left: (pos.x - size / 2) + "px",
top: (pos.y - size / 2) + "px",
zIndex: 50
});
elem.tooltipster({
position: "top",
offsetY: -10
});
elem.bind("mousedown", function(evt) {
evt.stopPropagation();
});
});
}).fail(function(xhr, err) {
console.log("Failed to update loot: " + err);
});
}
if (!itemNames) {
getJSON("itemnames.json", function(data) {
itemNames = data;
update();
}).fail(function(xhr, err) {
console.log("Failed to fetch item names: " + err);
update();
});
}
}
var resourceTypes = {
Stones: 0,
SulfurOre: 1,
MetalOre: 2,
MetalFragments: 3,
HighQualityMetalOre: 4,
CrudeOil: 5
};
var resourceColors = {
Stones: "#666",
SulfurOre: "#ff0",
MetalOre: "#f00",
MetalFragments: "#999",
HighQualityMetalOre: "#7f0000",
CrudeOil: "#222"
};
var resourceMaps = {};
function updateResourceMaps() {
var layer = $('#deposits');
getJSON("http://" + endpoint + "/resourcemap.json", function(data) {
if (!Array.isArray(data) || !Array.isArray(data[0])) {
console.log("Failed to fetch resource map: not a compatible array");
return;
}
var rows = data.length,
cols = data[0].length,
res = Math.round(server.world.size / (rows - 1)),
sizePerPixel = viewportSize / server.world.size,
size = res * sizePerPixel;
console.log("Resource map resolution: " + res + " (" + rows + "x" + cols + ")");
var stop = false;
Object.keys(resourceTypes).forEach(function(name, index) {
if (stop)
return;
if (resourceMaps.hasOwnProperty(name))
return;
var type = resourceTypes[name],
flagLow = 1 << (3 * type),
flagMedium = 1 << (3 * type + 1),
flagHigh = 1 << (3 * type + 2),
flagAll = flagLow | flagMedium | flagHigh,
color = resourceColors[name],
map = {};
map.canvas = document.createElement("canvas");
map.canvas.width = viewportSize;
map.canvas.height = viewportSize;
var ctx = map.ctx = map.canvas.getContext("2d");
resourceMaps[name] = map;
ctx.fillStyle = color;
var cx = viewportSize / 2,
cy = viewportSize / 2,
halfRows = Math.floor(rows / 2),
halfCols = Math.floor(cols / 2);
for (var y = halfRows; y >= -halfRows; --y) {
for (var x = -halfCols; x <= halfCols; ++x) {
var rx = cx + x * size,
ry = cy + y * size,
flags = data[halfRows + y][halfCols + x];
if (flags & flagAll) {
if (flags & flagLow) {
ctx.globalAlpha = 0.3;
} else if (flags & flagMedium) {
ctx.globalAlpha = 0.6;
} else if (flags & flagHigh) {
ctx.globalAlpha = 0.9;
}
ctx.fillRect(rx, ry, size, size);
}
}
}
map.canvas.style.position = "absolute";
layer.append(map.canvas);
});
}).fail(function(xhr, err) {
console.log("Failed to fetch resource map: " + err);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment