Files
gtav-src/tools_ng/web/dev/js/map_telemetry_old.js
T
2025-09-29 00:52:08 +02:00

2172 lines
63 KiB
JavaScript
Executable File

var vBoxWidth = 1200,
vBoxHeight = 900,
bgWidth = 900,
bgHeight = 1500,
clicked;
//Object used for local storage of the user selections - had to use underscores instead of hyphen
var pageData = {
build: 0,
level: 0,
platform: 0,
overlay_group: 0,
overlay_single: 0,
deaths_game_type_select: 0,
data_resolution: 0,
fps_game_type: 0,
build_config: 0,
metric: 0,
draw_list: 0,
statistics: 0,
automated_tests_check: false,
automated_tests_select: 0,
fps_off_mission_cutscene: false,
cps_metric: 0,
cps_draw_list: 0,
cps_statistics: 0,
pst_statistics: 0,
msf_game_type: 0,
msf_memory_type: 0,
msf_statistics: 0,
}
var totalAjaxRequests = 7;
var completedAjaxRequests = 0;
var forceUrlSuffix = "";
var fpsTelemetryData,
pstTelemetryData,
msfTelemetryData;
var interpolationColours = ["#E51616", "#E2C016", "#59E016"]; // red - yellow - green
function convert2WebXCoord(x) {
return ((x + project.map.coords.x)/project.map.scale);
}
function convert2WebYCoord(y) {
return (((-1)*y + project.map.coords.y)/project.map.scale);
}
function convert2WebCoords(p) {
return [convert2WebXCoord(p[0]), convert2WebYCoord(p[1])];
}
function convertFromWebXCoord(x) {
return (-1) * ((project.map.coords.x) - (x*project.map.scale));
}
function convertFromWebYCoord(y) {
return ((project.map.coords.y) - (y*project.map.scale));
}
function updateMapHeight() {
// Adjust the height of the map automatically
var windowHeight = $(window).height() - 3.0 * $("#sub-header").height();
//console.log(windowHeight);
$("#map-wrapper").css("height", windowHeight);
}
function initPage() {
// function from generic.js, variable from config file
//initHeaderAndFilters(headerAndFilters);
initHeaderAndFilters(null);
updateMapHeight();
var localData = retrieveLocalObject(config.currentFilename);
pageData = (localData) ? localData : pageData;
block();
$.ajax({
url: project.map.svgFile,
type: "GET",
data: {},
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var importedNode;
try {
importedNode = document.importNode(xml.documentElement, true);
}
catch(e) {
// IE case
importedNode = ieImportNode(xml.documentElement, document);
}
$("#map").append(importedNode);
},
error: function (xhr, ajaxOptions, thrownError){
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
},
complete: function() {
++completedAjaxRequests;
var svg = d3.select("#map svg")
.attr("width", $("#map").width())
.attr("height", $("#map").height())
.attr("enable-background", "new 0 0 " + bgWidth + " "+ bgHeight)
.call(svg_interact);
drawGrid();
}
});
$.ajax({
url: config.restHost + config.buildsAll,
type: "GET",
data: {},
dataType: "json",
success: function(json, textStatus, jqXHR) {
var builds = json.Items.sort(function(a, b) { return((a.Identifier > b.Identifier) ? -1 : 1); });
$.each(builds, function(i, build) {
if (!build.GameVersion)
return;
var titleExtra = [];
$("select#build").append(
$("<option />")
.html(function() {
var hasExtra = [];
var text = build.Identifier;
if (build.HasAutomatedEverythingStats) {
hasExtra.push("AE");
titleExtra.push("Automated Everything");
}
if (build.HasAutomatedMapOnlyStats) {
hasExtra.push("MO");
titleExtra.push("Automated Map Only");
}
if (build.HasMemShortfallStats) {
hasExtra.push("MS");
titleExtra.push("Memory Shortfall");
}
if (build.HasShapeTestStats) {
hasExtra.push("ST");
titleExtra.push("Shape Test");
}
return (hasExtra.length > 0) ? (text + " (" + hasExtra.join(",") + ")" ): text;
})
.attr("title", function() {
var title = build.Identifier;
return (titleExtra.length > 0) ? (title + " (" + titleExtra.join(", ") + ")" ): title;
})
.val(build.Identifier)
.attr("selected", function() {
return (pageData && pageData.build == build.Identifier) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
$.ajax({
url: config.restHost + config.levelsAll,
type: "GET",
data: {},
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var levels = convertLevelsXml(xml);
$.each(levels, function(i, level) {
$("select#level").append(
$('<option />')
.text(level.Name)
.val(level.Identifier)
.attr("selected", function() {
return (pageData && pageData.level == level.Identifier) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
// Platforms List
/*
$.ajax({
url: config.restHost + config.platformsAll,
type: "GET",
data: {},
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var platforms = convertPlatformsXml(xml);
$.each(platforms, function(i, platform) {
$("select#platform").append(
$('<option />')
.text(platform.Value)
.val(platform.Value)
.attr("selected", function() {
return (pageData && pageData.platform == platform.Value) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
*/
var platforms = getPlatforms();
$.each(platforms, function(i, platform) {
$("select#platform").append(
$('<option />')
.text(platform.Name)
.val(platform.Name)
.attr("selected", function() {
return (pageData && pageData.platform == platform.Name) ? "selected" : false;
})
);
});
++completedAjaxRequests;
// Overlay Groups
$.each(config.overlayGroupsAll, function(i, overlayGroup) {
$("select#overlay-group").append(
$('<option />')
.text(overlayGroup)
.val(overlayGroup)
.attr("selected", function() {
return (pageData && pageData.overlay_group == overlayGroup) ? "selected" : false;
})
);
});
// Overlays
$.each(config.overlaysAll, function(i, overlaySingle) {
$("select#overlay-single").append(
$('<option />')
.text(overlaySingle.Name)
.val(overlaySingle.Value)
.attr("selected", function() {
return (pageData && pageData.overlay_single == overlaySingle.Value) ? "selected" : false;
})
);
})
// Resolutions List
$.each(config.resolutionsAll, function(i, value) {
$("select#data-resolution").append(
$('<option />')
.text(value)
.val(value)
.attr("selected", function() {
return (pageData && pageData.data_resolution == value) ? "selected" : false;
})
);
});
/*
// Resolutions List
$.ajax({
url: config.restHost + config.resolutionsAll,
type: "GET",
data: {},
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var resolutions = convertResolutionsXml(xml);
$.each(resolutions, function(i, resolution) {
$("select#data-resolution").append(
$("<option />")
.text(resolution.BlockSize)
.val(resolution.Id)
.attr("selected", function() {
return (pageData && pageData.data_resolution == resolution.Id) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
*/
// Gametypes List
/*
$.ajax({
url: config.restHost + config.gametypesAll,
type: "GET",
data: {},
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var gametypes = convertGametypesXml(xml);
$.each(gametypes, function(i, gametype) {
$("select#fps-game-type").append(
$('<option />')
.text(gametype.Value)
.val(gametype.Value)
.attr("selected", function() {
return (pageData && pageData.fps_game_type == gametype.Value) ? "selected" : false;
})
);
$("select#deaths-game-type-select").append(
$('<option />')
.text(gametype.Value)
.val(gametype.Value)
.attr("selected", function() {
return (pageData && pageData.deaths_game_type_select == gametype.Value)
? "selected" : false;
})
);
$("select#msf-game-type").append(
$('<option />')
.text(gametype.Value)
.val(gametype.Value)
.attr("selected", function() {
return (pageData && pageData.msf_game_type == gametype.Value)
? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
*/
var gameTypes = getGameTypes();
$.each(gameTypes, function(i, gametype) {
$("select#fps-game-type").append(
$('<option />')
.text(gametype.Name)
.val(gametype.Name)
.attr("selected", function() {
return (pageData && pageData.fps_game_type == gametype.Name) ? "selected" : false;
})
);
$("select#deaths-game-type-select").append(
$('<option />')
.text(gametype.Name)
.val(gametype.Name)
.attr("selected", function() {
return (pageData && pageData.deaths_game_type_select == gametype.Name)
? "selected" : false;
})
);
$("select#msf-game-type").append(
$('<option />')
.text(gametype.Name)
.val(gametype.Name)
.attr("selected", function() {
return (pageData && pageData.msf_game_type == gametype.Name)
? "selected" : false;
})
);
});
++completedAjaxRequests;
// BuildConfigs List
/*
$.ajax({
url: config.restHost + config.buildConfigsAll,
type: "GET",
data: {},
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var buildConfigs = convertBuildConfigsXml(xml);
$.each(buildConfigs, function(i, buildConfig) {
$("select#build-config").append(
$('<option />')
.text(buildConfig.Value)
.val(buildConfig.Value)
.attr("selected", function() {
return (pageData && pageData.build_config == buildConfig.Value) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
*/
var buildConfigs = getBuildConfigs();
$.each(buildConfigs, function(i, buildConfig) {
$("select#build-config").append(
$('<option />')
.text(buildConfig.Name)
.val(buildConfig.Name)
.attr("selected", function() {
return (pageData && pageData.build_config == buildConfig.Name) ? "selected" : false;
})
);
});
++completedAjaxRequests;
// Metric List
$.each(config.metricAll, function(i, metric) {
$("select#metric").append(
$('<option />')
.text(metric)
.val(metric)
.attr("selected", function() {
return (pageData && pageData.metric == metric) ? "selected" : false;
})
);
});
// Draw List
$.ajax({
url: config.restHost + config.drawListAll,
type: "GET",
data: {},
dataType: "json",
success: function(json, textStatus, jqXHR) {
var drawList = json.sort(function(a, b) {return (a.GameName < b.GameName) ? -1 : 1});
//var drawList = convertDrawListXml(xml);
$.each(drawList, function(i, draw) {
$("select#draw-list").append(
$('<option />')
.text(draw.GameName)
.val(draw.GameName)
.attr("selected", function() {
return (pageData && pageData.draw_list == draw.GameName) ? "selected" : false;
})
);
$("select#cps-draw-list").append(
$('<option />')
.text(draw.GameName)
.val(draw.GameName)
.attr("selected", function() {
return (pageData && pageData.cps_draw_list == draw.GameName) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
/*
// Social Club Freemode Matches
$.ajax({
url: config.restHost + config.SCFreemodeNames,
type: "GET",
data: {type: "DEATHMATCH"},
dataType: "json",
success: function(deathmatches, textStatus, jqXHR) {
$.each(deathmatches, function(i, deathmatch) {
$("select#deathmatch-list").append(
$('<option />')
.text(deathmatch.Name + " (" + deathmatch.Creator + ")")
.val(deathmatch.UGCIdentifier)
.attr("title", deathmatch.Name + " (" + deathmatch.Creator + ") : " + deathmatch.Description)
)
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
++completedAjaxRequests;
}
});
*/
// Statistics List
$.each(config.statAll, function(i, stat) {
$("select#statistics").append(
$("<option />")
.text(stat.Name)
.val(stat.Value)
.attr("selected", function() {
return (pageData && pageData.statistics == stat.Value) ? "selected" : false;
})
);
$("select#cps-statistics").append(
$("<option />")
.text(stat.Name)
.val(stat.Value)
.attr("selected", function() {
return (pageData && pageData.cps_statistics == stat.Value) ? "selected" : false;
})
);
$("select#pst-statistics").append(
$("<option />")
.text(stat.Name)
.val(stat.Value)
.attr("selected", function() {
return (pageData && pageData.pst_statistics == stat.Value) ? "selected" : false;
})
);
$("select#msf-statistics").append(
$("<option />")
.text(stat.Name)
.val(stat.Value)
.attr("selected", function() {
return (pageData && pageData.msf_statistics == stat.Value) ? "selected" : false;
})
);
});
// Automated Tests check
if (pageData && pageData.automated_tests_check) {
$("#automated-tests input[type=checkbox]").prop("checked", true);
$("#automated-tests-select").attr("disabled", false);
}
else {
$("#automated-tests input[type=checkbox]").prop("checked", false);
$("#automated-tests-select").attr("disabled", true);
}
// Automated Tests select
$.each(config.automatedTestsAll, function(i, automatedTest) {
$("select#automated-tests-select").append(
$('<option />')
.text(automatedTest.Name)
.val(automatedTest.Value)
.attr("selected", function() {
return (pageData && pageData.automated_tests_select == automatedTest.Value) ? "selected" : false;
})
);
});
// For fps off missions/cutscene
if (pageData && pageData.fps_off_mission_cutscene) {
$("#fps-off-mission-cutscene").prop("checked", true);
}
else {
$("#fps-off-mission-cutscene").prop("checked", false);
}
// Memory Types select (for Memory Shortfall)
$.each(config.memoryTypesAll, function(i, memoryType) {
$("select#msf-memory-type").append(
$("<option />")
.text(memoryType.Name)
.val(memoryType.Value)
.attr("selected", function() {
return (pageData && pageData.msf_memory_type == memoryType.Value) ? "selected" : false;
})
);
});
toggleOverlayOptions($("select#overlay-single").val());
// Bind the events
$("#sub-header select").change(function() {
// If the select id is not the group overlay, then store the header options locally
if ($(this).attr("id") != "overlay-group") {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
}
if (($(this).attr("id") == "build") || ($(this).attr("id") == "level") || ($(this).attr("id") == "platform"))
//&& ($("select#overlay-single").val() == $("select#overlay-single option:eq(2)").val()))
updatePerformanceMetrics();
generateCustomOverlay();
});
$("#sub-header #filter-force").change(function() {
generateCustomOverlay();
});
$("select#overlay-single").change(function() {
toggleOverlayOptions($(this).val());
});
$(".overlay-options select").change(function() {
if ($(this).attr("id") != "deaths-list-select") {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
}
});
/*
$("#fps-overlay-options select").change(function() {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
*/
$("#fps-overlay-options select#metric").change(function() {
if ($(this).val() == config.fpsDrawListMetricName)
$("#fps-overlay-options select#draw-list").attr("disabled", false);
else
$("#fps-overlay-options select#draw-list").attr("disabled", true);
});
$("#fps-off-mission-cutscene").click(function() {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).is(":checked");
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
$("#automated-tests input[type=checkbox]").click(function() {
if ($(this).is(":checked")) {
$("#automated-tests-select").attr("disabled", false);
pageData[$(this).attr("id").replace(/\-/g, '_')] = true;
}
else {
$("#automated-tests-select").attr("disabled", true);
pageData[$(this).attr("id").replace(/\-/g, '_')] = false;
}
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
/*
$("#deaths-game-type select").change(function() {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
*/
$("#deaths-list select").change(function() {
highlightCircle($(this).val());
});
$("input#time-since-spawn").change(function() {
generateCustomOverlay();
});
/*
$("select#deathmatch-list").change(function() {
generateCustomOverlay();
});
*/
/*
$("#cps-overlay-options select").change(function() {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
*/
$("#cps-overlay-options select#cps-metric").change(function() {
if ($(this).val() == config.cpsDrawListMetricName)
$("#cps-overlay-options select#cps-draw-list").attr("disabled", false);
else
$("#cps-overlay-options select#cps-draw-list").attr("disabled", true);
});
/*
$("#pst-overlay-options select").change(function() {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
$("#msf-overlay-options select").change(function() {
pageData[$(this).attr("id").replace(/\-/g, '_')] = $(this).val();
storeLocalObject(config.currentFilename, pageData);
generateCustomOverlay();
});
*/
//$("#map-layers :checkbox").click(function(){
// The following declaration is faster than the latter
$("#map-layers input[type=checkbox]").click(function() {
var layer = d3.select("#map svg").select("g#" + $(this).val());
if ($(this).is(":checked")) {
layer
.transition()
.attr("opacity", 1);
}
else {
layer
.transition()
.attr("opacity", 0.01);
}
});
// Initialise the overlay
$("#performance-overlay").overlay({
mask: {
color: "#222",
loadSpeed: "fast",
opacity: 0.5,
},
top: "10%",
closeOnClick: false,
load: false,
});
$(window).resize(updateMapHeight);
$("#filter").click(function() {
generateCustomOverlay();
});
completePage();
}
function completePage() {
//console.log(completedAjaxRequests);
if (completedAjaxRequests < totalAjaxRequests) {
setTimeout(completePage, 500)
}
else {
unBlock();
updatePerformanceMetrics();
// Generate overlay if an overlay group is selected by default
generateCustomOverlay();
}
}
function updatePerformanceMetrics() {
block();
$.ajax({
url: config.restHost + config.capturePerformanceMetrics,
type: "GET",
dataType: "json",
data: {
build: $("select#build").val(),
level: $("select#level").val(),
platform: $("select#platform").val(),
},
async: false,
success: function(json, textStatus, jqXHR) {
$("select#cps-metric").empty();
$.each(json, function(i, metric) {
$("select#cps-metric").append(
$('<option />')
.text(metric)
.val(metric)
.attr("selected", function() {
return (pageData && pageData.cps_metric == metric) ? "selected" : false;
})
);
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
unBlock();
}
});
}
function drawGrid() {
var gridStep = 500/project.map.scale; // The step of the grid in map coordinates
var grid = d3.select("#map svg")
.append("svg:g")
.attr("id", "grid");
var xAxisDataNeg = d3.range(convert2WebXCoord(0), 0, -gridStep);
var xAxisDataPos = d3.range(convert2WebXCoord(0), bgWidth, gridStep);
var yAxisDataNeg = d3.range(convert2WebYCoord(0), 0, -gridStep);
var yAxisDataPos = d3.range(convert2WebYCoord(0), bgHeight, gridStep);
grid.selectAll("line.vertical")
.data(xAxisDataNeg.concat(xAxisDataPos))
.enter()
.append("svg:line")
.attr("x1", function(d) {return d;})
.attr("y1", 0)
.attr("x2", function(d) {return d;})
.attr("y2", bgHeight)
.attr("class", "map-grid");
grid.selectAll("line.horizontal")
.data(yAxisDataNeg.concat(yAxisDataPos))
.enter()
.append("svg:line")
.attr("x1", 0)
.attr("y1", function(d) {return d;})
.attr("x2", bgWidth)
.attr("y2", function(d) {return d;})
.attr("class", "map-grid");
}
function drawFpsHeatmap(cached) {
var resolution = Number($("select#data-resolution").val()),
metric = $("select#metric").val(),
stat = capitaliseString($("select#statistics").val());
if (!cached) {
var pValues = {
//ForceUrlSuffix: forceUrlSuffix,
ElementKeyName: "Name",
ElementValueName: "Value",
Pairs: {
"BuildIdentifier": $("select#build").val(),
"LevelIdentifier": $("select#level").val(),
"PlatformName": $("select#platform").val(),
"Resolution" : resolution,
"BuildConfigName" : $("select#build-config").val(),
"GameTypeName" : $("select#fps-game-type").val(),
"DrawListName" : $("select#draw-list").val(),
"OffMissionAndCutsceneOnly" : $("#fps-off-mission-cutscene").is(":checked"),
},
};
if ($("#automated-tests input[type=checkbox]").is(":checked")) {
var autoTestNum = parseInt($("#automated-tests-select").val());
//console.log(autoTestNum);
pValues.Pairs["AutomatedTestNumber"] = autoTestNum;
}
var restEndpoint, restEndpointAsync;
if ($("#fps-overlay-options select#metric :selected").val() == config.fpsDrawListMetricName) { // == DrawLists
restEndpoint = config.fpsDrawListPerformanceStats,
restEndpointAsync = config.fpsDrawListPerformanceStatsAsync + forceUrlSuffix;
}
else {
restEndpoint = config.fpsPerformanceStats,
restEndpointAsync = config.fpsPerformanceStatsAsync + forceUrlSuffix;
}
var req = new ReportRequest(config.restHost + restEndpoint,
"json",
config.restHost + restEndpointAsync,
config.restHost + config.reportsQueryAsync);
req.sendSingleAsyncRequest(pValues, handleFpsPerformanceResults);
}
else {
handleFpsPerformanceResults(fpsTelemetryData);
}
function handleFpsPerformanceResults(telemetryData) {
// Save for later
fpsTelemetryData = telemetryData
var valueFunc = function(d) {
return ((metric != config.fpsDrawListMetricName) ? d[stat + metric] : d[stat + "EntityCount"]);
}
generateGenericHeatmap(telemetryData, resolution, valueFunc, "fps-overlay-options");
}
} // end of drawFpsHeatmap()
function drawShapeTestHeatmap(cached) {
var resolution = 100;
if (!cached) {
var pValues = {
//ForceUrlSuffix: forceUrlSuffix,
ElementKeyName: "Name",
ElementValueName: "Value",
Pairs: {
"BuildIdentifier": $("select#build").val(),
"PlatformName": $("select#platform").val(),
"LevelIdentifier": $("select#level").val(),
"Resolution" : resolution,
}
};
var req = new ReportRequest(config.restHost + config.physicsShapeTestStats,
"json",
config.restHost + config.physicsShapeTestStatsAsync + forceUrlSuffix,
config.restHost + config.reportsQueryAsync);
req.sendSingleAsyncRequest(pValues, handlePhysicsShapeTestResults);
}
else {
handlePhysicsShapeTestResults(pstTelemetryData);
}
function handlePhysicsShapeTestResults(telemetryData) {
// Save for later
pstTelemetryData = telemetryData
var valueFunc = function(d) {
return d[capitaliseString($("select#pst-statistics").val())];
}
generateGenericHeatmap(telemetryData, resolution, valueFunc, "pst-overlay-options");
}
} // end of drawShapeTestHeatmap()
function drawShortfallHeatmap(cached) {
var resolution = 100;
var memoryType = $("select#msf-memory-type").val();
var stat = capitaliseString($("select#msf-statistics").val());
if (!cached) {
var pValues = {
//ForceUrlSuffix: forceUrlSuffix,
ElementKeyName: "Name",
ElementValueName: "Value",
Pairs: {
"BuildIdentifier": $("select#build").val(),
"PlatformName": $("select#platform").val(),
"LevelIdentifier": $("select#level").val(),
"Resolution" : resolution,
}
};
var req = new ReportRequest(config.restHost + config.memoryShortfallStats,
"json",
config.restHost + config.memoryShortfallStatsAsync + forceUrlSuffix,
config.restHost + config.reportsQueryAsync);
req.sendSingleAsyncRequest(pValues, handleShortfallResults);
}
else {
handleShortfallResults(msfTelemetryData);
}
function handleShortfallResults(telemetryData) {
// Save for later
msfTelemetryData = telemetryData
//console.log(telemetryData);
var valueFunc = function(d) {
//console.log(d[stat + memoryType]);
return d[stat + memoryType];
};
generateGenericHeatmap(telemetryData, resolution, valueFunc, "msf-overlay-options");
}
} // end of drawShortfallHeatmap()
function generateGenericHeatmap(telemetryData, resolution, valueFunc, domElement) {
showMsgWhenNoData(telemetryData);
var min = 0, max = 0;
$.each(telemetryData, function(i ,d) {
min = ((valueFunc(d) < min) ? valueFunc(d) : min);
max = ((valueFunc(d) > max) ? valueFunc(d) : max);
});
var med = ((min+max)/2);
var thresholdSlider = $("#" + domElement + " div.threshold-slider");
thresholdSlider.slider("option", "min", min);
thresholdSlider.slider("option", "max", max);
thresholdSlider.slider("refresh");
var valuesSlider = $("#" + domElement + " div.value-slider");
valuesSlider.slider("option", "min", min);
valuesSlider.slider("option", "max", max);
$("#" + domElement + " span.value-min").text(min.toFixed(2));
$("#" + domElement + " span.value-max").text(max.toFixed(2));
if ((valuesSlider.slider("values")[0] == min) && (valuesSlider.slider("values")[1] == min)) {
valuesSlider.slider("values", 0, min);
valuesSlider.slider("values", 1, max);
}
valuesSlider.slider("refresh");
rangeSliderValues = valuesSlider.slider("values");
var heatmapSliderValues = $("#" + domElement + " div.heatmap-slider-placeholder").slider("values");
var colourInterpolator = getColourInterpolator(rangeSliderValues[0], rangeSliderValues[1],
heatmapSliderValues[1], heatmapSliderValues[0]);
$("#" + domElement + " span.heatmap-gradient" + " span.heatmap-min").text(rangeSliderValues[0].toFixed(2));
$("#" + domElement + " span.heatmap-gradient" + " span.heatmap-med").text(
((rangeSliderValues[0] + rangeSliderValues[1]) / 2).toFixed(2)
);
$("#" + domElement + " span.heatmap-gradient" + " span.heatmap-max").text(rangeSliderValues[1].toFixed(2));
var heatmap = d3.select("#map svg").append("svg:g")
.attr("id", "telemetry-overlay")
.attr("opacity", 0.01);
heatmap
.selectAll("rect")
.data(telemetryData)
.enter()
.append("svg:rect")
.attr("x", function(d) {
return convert2WebXCoord(d.Location.X);
})
.attr("y", function(d) {
return convert2WebYCoord(d.Location.Y + resolution);
})
.attr("width", resolution/project.map.scale)
.attr("height", resolution/project.map.scale)
.attr("fill", function(d) {
return colourInterpolator(valueFunc(d));
})
.attr("visibility", function(d) { // Hide if below the threshold limit
return (valueFunc(d) >= thresholdSlider.slider("value")) ? "visible" : "hidden";
})
.on("click", click)
.append("title")
.text(function(d) {
var title = "Centre (x=" + (d.Location.X + resolution/2)
+ ", y=" + (d.Location.Y + resolution/2) + ")"
+ "\nValue : " + valueFunc(d).toFixed(2);
//console.log(d.SampleSize);
if ((typeof d.SampleSize) !== "undefined")
title += "\nSample Size : " + d.SampleSize;
return (title);
});
heatmap
.transition()
.attr("opacity", 1);
function click(d) {
if (d && clicked !== d) {
clicked = d;
}
else {
clicked = null;
}
heatmap.selectAll("rect")
.classed("active", clicked && function(d) { return d === clicked; });
}
}
// end of generateGenericHeatmap
function drawCpsHeatmap() {
var cpsMetric = $("select#cps-metric").val();
if (!cpsMetric)
return;
var restOptions = {
build: $("select#build").val(),
level: $("select#level").val(),
platform: $("select#platform").val(),
//resolution: 2,
metric: cpsMetric,
statistic: $("select#cps-statistics :selected").text(),
}
if (cpsMetric == config.cpsDrawListMetricName)
restOptions["drawList"] = $("select#cps-draw-list").val();
block();
$.ajax({
url: config.restHost + config.capturePerformanceStats,
type: "GET",
data: restOptions,
dataType: "json",
success: function(json, textStatus, jqXHR) {
//console.log(json)
var colour = d3.scale.linear()
.domain([33, 50, 66])
.range(interpolationColours);
//var resolution = parseInt($("select#data-resolution :selected").text());
var resolution = 100;
var heatmap = d3.select("#map svg").append("svg:g")
.attr("id", "telemetry-overlay")
.attr("opacity", 0.01);
showMsgWhenNoData(json.Items);
heatmap
.selectAll("rect")
.data(json.Items)
.enter()
.append("svg:rect")
.attr("x", function(d) {
return convert2WebXCoord(Number(d.Location.X));
})
.attr("y", function(d) {
return convert2WebYCoord(Number(d.Location.Y) + resolution);
})
.attr("width", resolution/project.map.scale)
.attr("height", resolution/project.map.scale)
.attr("fill", function(d) {
return colour(d.Value);
})
.on("mouseover", function() {
d3.select(this).classed("active", true);
})
.on("mouseout", function() {
d3.select(this).classed("active", false);
})
.on("click", showPerformanceDetails)
//.on("dblclick", showPerformanceDetails)
.append("title")
.text(function(d) {
var title = "Centre (x=" + (d.Location.X + resolution/2)
+ ", y=" + (d.Location.Y + resolution/2) + ")"
+ "\nValue : " + d.Value.toFixed(2)
+ "\nClick for Full Report";
return (title);
});
heatmap
.transition()
.attr("opacity", 1);
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
},
complete: function() {
unBlock();
}
}); // end of $.ajax()
}
function showPerformanceDetails(d) {
var resolution = 100;
var restOptions = {
build: $("select#build").val(),
level: $("select#level").val(),
platform: $("select#platform").val(),
resolution: 2,
x: d.Location.X + (resolution/2),
y: d.Location.Y + (resolution/2),
}
block();
var summary;
$.ajax({
url: config.restHost + config.capturePerformanceSummary,
type: "GET",
data: restOptions,
dataType: "json",
async: true,
success: function(json, textStatus, jqXHR) {
summary = json;
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
},
complete: function() {
}
}); // end of summary $.ajax()
$.ajax({
url: config.restHost + config.capturePerformanceZones,
type: "GET",
data: restOptions,
dataType: "json",
async: true,
success: function(json, textStatus, jqXHR) {
//console.log(json)
populatePerformanceReport(json, summary);
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
},
complete: function() {
var legendText = "Report for Cell with Centre ("
+ restOptions.x + ", " + restOptions.y + ")";
$("#performance-overlay fieldset legend").text(legendText);
$("#performance-overlay").overlay().load();
unBlock();
}
}); // end of zones $.ajax()
}
function populatePerformanceReport(data, summary) {
$("#performance-overlay table").empty();
// FPS RESULT
var fpsSum = summary.FpsInfo;
$("#fps-results")
.append(
$("<tr>")
.append(
$("<th>")
.addClass("title")
.attr("colspan", 4)
.text("Fps Result")
)
)
.append(
$("<tr>")
.append(
$("<th>").text("Average (ms)")
)
.append(
$("<th>").text("Max (ms)")
)
.append(
$("<th>").text("Min (ms)")
)
.append(
$("<th>").text("Standard Deviation (ms)")
)
)
.append(
$("<tr>")
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([fpsSum.AverageMin, fpsSum.AverageAverage, fpsSum.AverageMax])
.range(interpolationColours);
return colour(data.FpsResult.Average);
})
.text(data.FpsResult.Average.toFixed(2) + " (" + fpsSum.AverageAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([fpsSum.MaxMin, fpsSum.MaxAverage, fpsSum.MaxMax])
.range(interpolationColours);
return colour(data.FpsResult.Max);
})
.text(data.FpsResult.Max.toFixed(2) + " (" + fpsSum.MaxAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([fpsSum.MinMin, fpsSum.MinAverage, fpsSum.MinMax])
.range(interpolationColours);
return colour(data.FpsResult.Min);
})
.text(data.FpsResult.Min.toFixed(2) + " (" + fpsSum.MinAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.text(data.FpsResult.StandardDeviation.toFixed(2))
)
);
// THREAD RESULTS
var threadSum = [];
$.each(summary.ThreadInfo, function(i, threadInfo) {
threadSum[threadInfo.Name] = threadInfo;
});
//console.log(threadSum);
$("#thread-results")
.append(
$("<tr>")
.append(
$("<th>")
.addClass("title")
.attr("colspan", 5)
.text("Thread Results")
)
)
.append(
$("<tr>")
.append(
$("<th>").text("Name")
)
.append(
$("<th>").text("Average (ms)")
)
.append(
$("<th>").text("Max (ms)")
)
.append(
$("<th>").text("Min (ms)")
)
.append(
$("<th>").text("Standard Deviation (ms)")
)
);
$.each(data.ThreadResults, function(i, threadResult) {
$("<tr>")
.append(
$("<td>").text(threadResult.Name)
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([threadSum[threadResult.Name].AverageMin,
threadSum[threadResult.Name].AverageAverage,
threadSum[threadResult.Name].AverageMax])
.range(interpolationColours);
return colour(threadResult.Average);
})
.text(threadResult.Average.toFixed(2) + " (" + threadSum[threadResult.Name].AverageAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([threadSum[threadResult.Name].MaxMin,
threadSum[threadResult.Name].MaxAverage,
threadSum[threadResult.Name].MaxMax])
.range(interpolationColours);
return colour(threadResult.Max);
})
.text(threadResult.Max.toFixed(2) + " (" + threadSum[threadResult.Name].MaxAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([threadSum[threadResult.Name].MinMin,
threadSum[threadResult.Name].MinAverage,
threadSum[threadResult.Name].MinMax])
.range(interpolationColours);
return colour(threadResult.Min);
})
.text(threadResult.Min.toFixed(2) + " (" + threadSum[threadResult.Name].MinAverage.toFixed(2) + ")")
)
.append(
$("<td>").text(threadResult.StandardDeviation.toFixed(2))
)
.appendTo("#thread-results");
});
// CPU RESULTS
var cpuSum = [];
$.each(summary.CpuInfo, function(i, cpuInfo) {
cpuSum[cpuInfo.Name] = cpuInfo;
});
$("#cpu-results")
.append(
$("<tr>")
.append(
$("<th>")
.addClass("title")
.attr("colspan", 6)
.text("Cpu Results")
)
)
.append(
$("<tr>")
.append(
$("<th>").text("Name")
)
.append(
$("<th>").text("Set")
)
.append(
$("<th>").text("Average (ms)")
)
.append(
$("<th>").text("Max (ms)")
)
.append(
$("<th>").text("Min (ms)")
)
.append(
$("<th>").text("Standard Deviation (ms)")
)
);
$.each(data.CpuResults, function(i, cpuResult) {
$("<tr>")
.append(
$("<td>").text(cpuResult.Name)
)
.append(
$("<td>").text(cpuResult.Set)
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([cpuSum[cpuResult.Name].AverageMin,
cpuSum[cpuResult.Name].AverageAverage,
cpuSum[cpuResult.Name].AverageMax])
.range(interpolationColours);
return colour(cpuResult.Average);
})
.text(cpuResult.Average.toFixed(2) + " (" + cpuSum[cpuResult.Name].AverageAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([cpuSum[cpuResult.Name].MaxMin,
cpuSum[cpuResult.Name].MaxAverage,
cpuSum[cpuResult.Name].MaxMax])
.range(interpolationColours);
return colour(cpuResult.Max);
})
.text(cpuResult.Max.toFixed(2) + " (" + cpuSum[cpuResult.Name].MaxAverage.toFixed(2) + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([cpuSum[cpuResult.Name].MinMin,
cpuSum[cpuResult.Name].MinAverage,
cpuSum[cpuResult.Name].MinMax])
.range(interpolationColours);
return colour(cpuResult.Min);
})
.text(cpuResult.Min.toFixed(2) + " (" + cpuSum[cpuResult.Name].MinAverage.toFixed(2) + ")")
)
.append(
$("<td>").text(cpuResult.StandardDeviation.toFixed(2))
)
.appendTo("#cpu-results");
});
// Draw List RESULTS
var drawListSum = [];
$.each(summary.DrawListInfo, function(i, drawListInfo) {
drawListSum[drawListInfo.Name] = drawListInfo;
});
$("#draw-list-results")
.append(
$("<tr>")
.append(
$("<th>")
.addClass("title")
.attr("colspan", 5)
.text("Draw List Results")
)
)
.append(
$("<tr>")
.append(
$("<th>").text("Name")
)
.append(
$("<th>").text("Average (ms)")
)
.append(
$("<th>").text("Max (ms)")
)
.append(
$("<th>").text("Min (ms)")
)
.append(
$("<th>").text("Standard Deviation (ms)")
)
);
$.each(data.DrawListResults, function(i, drawListResult) {
$("<tr>")
.append(
$("<td>").text(drawListResult.Name)
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([drawListSum[drawListResult.Name].AverageMin,
drawListSum[drawListResult.Name].AverageAverage,
drawListSum[drawListResult.Name].AverageMax])
.range(interpolationColours);
return colour(drawListResult.Average);
})
.text(drawListResult.Average + " (" + drawListSum[drawListResult.Name].AverageAverage + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([drawListSum[drawListResult.Name].MaxMin,
drawListSum[drawListResult.Name].MaxAverage,
drawListSum[drawListResult.Name].MaxMax])
.range(interpolationColours);
return colour(drawListResult.Max);
})
.text(drawListResult.Max + " (" + drawListSum[drawListResult.Name].MaxAverage + ")")
)
.append(
$("<td>")
.css("color", function() {
var colour = d3.scale.linear()
.domain([drawListSum[drawListResult.Name].MinMin,
drawListSum[drawListResult.Name].MinAverage,
drawListSum[drawListResult.Name].MinMax])
.range(interpolationColours);
return colour(drawListResult.Min);
})
.text(drawListResult.Min + " (" + drawListSum[drawListResult.Name].MinAverage + ")")
)
.append(
$("<td>").text(drawListResult.StandardDeviation.toFixed(2))
)
.appendTo("#draw-list-results");
});
}
function drawDeaths() {
var restUrl = config.restHost + config.buildsPath
+ $("select#build").val() + "/"
+ $("select#overlay-group").val() + "/"
+ $("select#overlay-single").val();
var restOptions = {
level: $("select#level").val(),
platform: $("select#platform").val(),
gameType: $("select#deaths-game-type-select").val(),
}
$("select#deaths-list-select").empty();
block();
$.ajax({
url: restUrl,
type: "GET",
data: restOptions,
dataType: "xml",
success: function(xml, textStatus, jqXHR) {
var deaths = convertDeathTelemetryStatXml(xml);
showMsgWhenNoData(deaths);
var deathCircles = d3.select("#map svg")
.append("svg:g")
.attr("id", "telemetry-overlay")
.attr("opacity", 0.01);
deathCircles
.selectAll("circle")
.data(deaths)
.enter()
.append("svg:circle")
.attr("id", function(d, i) {return "circle_" + i;})
.attr("cx", function(d) {
return convert2WebXCoord(d.x);
})
.attr("cy", function(d) {
return convert2WebYCoord(d.y);
})
.attr("r", 2)
.attr("fill", config.chartColour1)
.attr("stroke", config.chartColour3)
.attr("stroke-width", 0.3)
.attr("opacity", 0.8)
.append("title")
.text(function(d, i) {
var title = "Location: (x=" + d.x
+ ", y=" + d.y + ")";
if (d.MissionName)
title += ", \nMission Name: " + d.MissionName;
if (d.DeathTimestamp && d.MissionStarted)
title += ", \nTime on Mission: "
+ formatSecs(dateStringsDiffInSecs(d.DeathTimestamp - d.MissionStarted));
if (d.WantedLevel)
title += ", \nWanted Level: " + d.WantedLevel;
if (d.DeathTimestamp && d.WantedLevelStarted)
title += ", \nTime with Wanted Level: "
+ formatSecs(dateStringsDiffInSecs(d.DeathTimestamp - d.WantedLevelStarted));
if (d.WeaponName)
title += ", \nWeapon: " + d.WeaponName;
if (d.KillerIsPlayer == "true")
title += ", \nThe killer was a player";
if (d.KillerIsLocalPlayer == "true")
title += ", \nThe killer was a local player";
if (d.KillerInVehicle == "true")
title += ", \nThe killer was on a vehicle";
if (d.KillerRunning == "true")
title += ", \nThe killer was running";
if (d.KillerSprinting == "true")
title += ", \nThe killer was sprinting";
if (d.KillerCrouching == "true")
title += ", \nThe killer was crouching";
if (d.VictimIsPlayer == "true")
title += ", \nThe victim was a player";
if (d.VictimIsLocalPlayer == "true")
title += ", \nThe victim was a local player";
if (d.VictimInVehicle == "true")
title += ", \nThe victim was on a vehicle";
if (d.VictimRunning == "true")
title += ", \nThe victim was running";
if (d.VictimSprinting == "true")
title += ", \nThe victim was sprinting";
if (d.VictimCrouching == "true")
title += ", \nThe victim was crouching";
// Populate the html select list
$("select#deaths-list-select").append(
$('<option />')
.text(i+1 + ". Death at (x=" + d.x
+ ", y=" + d.y + ")")
.val(i)
.attr("title", title)
);
return (title);
});
deathCircles
.transition()
.attr("opacity", 1);
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
},
complete: function() {
unBlock();
}
}); // end of $.ajax()
} // End of drawDeaths
function highlightCircle(id) {
var svg = d3.select("#map svg")
.selectAll("g#telemetry-overlay");
svg.select("circle#circle_" + id)
.classed("active", true)
.transition()
.attr("r", 10)
//.attr("stroke-width", 3)
.duration(config.transitionDuration)
.each("end", function() {
d3.select(this)
.classed("active", false)
.transition()
.attr("r", 2) // back to normal
//.attr("stroke-width", 3)
.delay(config.transitionDelay)
});
}
function drawSpawnHeatmap() {
var radius = 2;
var pValues = {
//ForceUrlSuffix: forceUrlSuffix,
ElementKeyName: "Name",
ElementValueName: "Value",
Pairs: {
"BuildIdentifiers": $("select#build").val(),
"PlatformNames": $("select#platform").val(),
"DeathmatchUGCIdentifier": $("select#deathmatch-list").val(),
"BlockSize": radius,
"TimeSinceSpawn": $("input#time-since-spawn").val(),
}
};
var req = new ReportRequest(config.restHost + config.spawnStats,
"json",
config.restHost + config.spawnStatsAsync + forceUrlSuffix,
config.restHost + config.reportsQueryAsync);
req.sendSingleAsyncRequest(pValues, handleSpawnResults);
function handleSpawnResults(telemetryData) {
showMsgWhenNoData(telemetryData);
if (telemetryData.length == 0)
return;
var valueFunc = function(d) {return d.Occurrences};
var xFunc = function(d) {return d.Location.X};
var yFunc = function(d) {return d.Location.Y};
generateCoolHeatmap(telemetryData, radius, valueFunc, xFunc, yFunc);
}
}
function generateCoolHeatmap(telemetryData, radius, valueFunc, xFunc, yFunc) {
/*
var heatmap = d3.select("#map svg")
.append("svg:g")
//.attr("id", "telemetry-overlay")
.attr("opacity", 0.01);
heatmap
.selectAll("circle")
.data(telemetryData)
.enter()
.append("svg:circle")
.attr("id", function(d, i) {return "circle_" + i;})
.attr("cx", function(d) {
return convert2WebXCoord(xFunc(d));
})
.attr("cy", function(d) {
return convert2WebYCoord(yFunc(d));
})
.attr("r", radius/scale)
.attr("fill", "rgb(0, 255, 0)")
.attr("opacity", 0.4)
.append("title")
.text(function(d) {
var title = "Centre (x=" + (xFunc(d))
+ ", y=" + (yFunc(d)) + ")"
+ "\nOccurences : " + valueFunc(d);
return (title);
});
heatmap
.transition()
.attr("opacity", 1);
*/
// Clean any canvas elements
$("#map canvas").remove();
var config = {
"radius": 10,
"element": "map",
"visible": true,
"opacity": 60,
"gradient": { 0: "rgb(0, 255, 0)", 0.5: "yellow", 1: "rgb(255, 0, 0)" }
};
var heatmap = heatmapFactory.create(config);
var heatmapData = {
max: 0,
data: [],
};
// Var for the max value
var max = 0;
// We need to find the rectangle that includes all the points so we can generate only a small
// heatmap image of the desired area.
var upperLeft = {x: telemetryData[0].Location.X, y: telemetryData[0].Location.Y};
var lowerRight = {x: telemetryData[0].Location.X, y: telemetryData[0].Location.Y};
$.each(telemetryData, function(i, point) {
// find the maximum value
max = (max < valueFunc(point)) ? valueFunc(point) : max;
// We need to find the upperLeft and lowerRight points in real game coordinates that include all the points
// upperLeft has minimum X and maximum Y
upperLeft.x = (xFunc(point) < upperLeft.x) ? xFunc(point) : upperLeft.x;
upperLeft.y = (yFunc(point) > upperLeft.y) ? yFunc(point) : upperLeft.y;
// lowerRight has maximum X and minimum or equal Y
lowerRight.x = (xFunc(point) > lowerRight.x) ? xFunc(point) : lowerRight.x;
lowerRight.y = (yFunc(point) < lowerRight.y) ? yFunc(point) : lowerRight.y;
});
// Save the max value to the heatmap data
heatmapData["max"] = max;
// Add the radius to the rectangle corner points
var margin = 50;
upperLeft.x -= (radius + margin);
upperLeft.y += (radius + margin);
lowerRight.x += (radius + margin);
lowerRight.y -= (radius + margin);
//console.log(max);
//console.log(upperLeft);
//console.log(lowerRight);
// The width and the height of the heatmap fragment will be
fragmentWidth = lowerRight.x - upperLeft.x;
fragmentHeight = upperLeft.y - lowerRight.y;
//console.log(fragmentWidth);
//console.log(fragmentHeight);
// Crate a new fragment coordinates system where 0.0 is the top left // NEEDS WORK
// new (0, 0) will be (upperLeft.x, upperLeft.y)
function convertXtoFragmentCoords(x) {
// Subtract new (0, 0) from the x coord, upperLeft.x is the minimum x
return x - upperLeft.x;
}
function convertYtoFragmentCoords(y) {
// Subtract y coord from the new (0, 0), upperLeft.y is the maximum y
return upperLeft.y - y;
}
$("#map canvas")
.attr("id", "heatmapjs-canvas")
.attr("width", fragmentWidth)
.attr("height", fragmentHeight)
.css("display", "none");
$.each(telemetryData, function(i, point) {
heatmapData.data.push({
x: convertXtoFragmentCoords(xFunc(point)),
y: convertYtoFragmentCoords(yFunc(point)),
count: valueFunc(point)});
});
heatmap.store.setDataSet(heatmapData);
//console.log(heatmapData);
// Save the canvas to a file object as png image
var canvas = document.getElementById("heatmapjs-canvas");
var image = canvas.toDataURL("image/png");
//window.location = image;
// Add the scaled image to the correct position on the svg map (use the previously calculated upperLeft point)
d3.select("#map svg")
.append("svg:g")
.attr("id", "telemetry-overlay")
.append("svg:image")
.attr("xlink:href", image)
.attr("width", fragmentWidth/project.map.scale)
.attr("height", fragmentHeight/project.map.scale)
.attr("x", function() {return convert2WebXCoord(upperLeft.x)})
//.attr("x", convert2WebXCoord(upperLeft.x))
.attr("y", function() {return convert2WebYCoord(upperLeft.y)});
}
// end of generateCoolHeatmap
function removeOverlay() {
d3.select("#map svg")
.selectAll("g#telemetry-overlay")
.transition()
.attr("opacity", 0.01)
.remove();
}
function generateCustomOverlay(useCached) {
removeOverlay();
if ($("#filter-force").is(":checked"))
forceUrlSuffix = config.reportForceSuffix;
else
forceUrlSuffix = "";
//console.log(forceUrlSuffix);
if ($("select#overlay-group").val() == $("select#overlay-group option:eq(1)").val()) { // == "Telemetry Group"
if ($("select#overlay-single").val() == $("select#overlay-single option:eq(0)").val()) { // == "Fps"
drawFpsHeatmap(useCached);
}
else if ($("select#overlay-single").val() == $("select#overlay-single option:eq(1)").val()) { // == "ShapeTest"
drawShapeTestHeatmap(useCached);
}
else if ($("select#overlay-single").val() == $("select#overlay-single option:eq(2)").val()) { // == "Shortfall"
drawShortfallHeatmap(useCached);
}
else if ($("select#overlay-single").val() == $("select#overlay-single option:eq(3)").val()) { // == "Cps"
drawCpsHeatmap(useCached);
}
else if ($("select#overlay-single").val() == $("select#overlay-single option:eq(4)").val()) { // == "Deaths"
drawDeaths(useCached);
}
else if ($("select#overlay-single").val() == $("select#overlay-single option:eq(5)").val()) { // == "Spawns"
drawSpawnHeatmap(useCached);
}
}
}
function toggleOverlayOptions(selectedValue) {
$(".overlay-options").hide();
var selectedOverlayID;
if (selectedValue == $("select#overlay-single option:eq(0)").val()) {// == "FPS"
$("#fps-overlay-options").show("blind", {}, "slow");
selectedOverlayID = "fps-overlay-options";
}
else if (selectedValue == $("select#overlay-single option:eq(1)").val()) {// == "PST"
$("#pst-overlay-options").show("blind", {}, "slow");
selectedOverlayID = "pst-overlay-options";
}
else if (selectedValue == $("select#overlay-single option:eq(2)").val()) {// == "MSF"
$("#msf-overlay-options").show("blind", {}, "slow");
selectedOverlayID = "msf-overlay-options";
}
else if (selectedValue == $("select#overlay-single option:eq(3)").val()) {// == "CPS"
$("#cps-overlay-options").show("blind", {}, "slow");
}
else if (selectedValue == $("select#overlay-single option:eq(4)").val()) { // == "Deaths"
$("#deaths-overlay-options").show("blind", {}, "slow");
}
else if (selectedValue == $("select#overlay-single option:eq(5)").val()) { // == "Spawn"
$("#spawn-overlay-options").show("blind", {}, "slow");
}
if (selectedOverlayID) {
var defaultMinHue = 0,
defaultMaxHue = 240,
defaultMinHueSlider = 0,
defaultMaxHueSlider = 120;
$("#" + selectedOverlayID + " div.heatmap-slider-placeholder").slider({
range: true,
min: defaultMinHue,
max: defaultMaxHue,
values: [defaultMinHueSlider, defaultMaxHueSlider],
stop: function(event, ui ) { // fire when mouse is released
generateHeatmapGradient(selectedOverlayID + " span.heatmap-gradient",
//ui.values[0], ui.values[1]);
ui.values[1], ui.values[0]);
generateCustomOverlay(true);
}
});
$("#" + selectedOverlayID + " div.value-slider").slider({
range: true,
min: 0,
max: 0,
values: [0, 0],
stop: function(event, ui ) { // fire when mouse is released
generateCustomOverlay(true);
}
});
$("#" + selectedOverlayID + " div.threshold-slider").slider({
min: 0,
max: 0,
value: 0,
stop: function(event, ui ) { // fire when mouse is released
$(this).next().text(ui.value.toFixed(2));
generateCustomOverlay(true);
}
});
generateHeatmapGradient(selectedOverlayID + " span.heatmap-slider", defaultMinHue, defaultMaxHue);
generateHeatmapGradient(selectedOverlayID + " span.heatmap-gradient",
defaultMaxHueSlider, defaultMinHueSlider);
}
}
function showMsgWhenNoData(array) {
if (array.length < 1)
Sexy.alert(config.noDataMapText);
}
function generateHeatmapGradient(elementID, minHue, maxHue) {
var canvas = $("#" + elementID + " canvas")[0];
var context = canvas.getContext("2d");
context.rect(0, 0, canvas.width, canvas.height);
// add linear gradient
var grd = context.createLinearGradient(0, 0, canvas.width, 0);
var s = 0.9, v = 0.9;
var hueStep = (maxHue - minHue) / 5;
grd.addColorStop(0, hsv2hex(minHue, s, v));
grd.addColorStop(0.167, hsv2hex(minHue+hueStep, s, v));
grd.addColorStop(0.333, hsv2hex(minHue+2*hueStep, s, v));
grd.addColorStop(0.5, hsv2hex(minHue+3*hueStep, s, v));
grd.addColorStop(0.667, hsv2hex(minHue+4*hueStep, s, v));
grd.addColorStop(0.833, hsv2hex(minHue+5*hueStep, s, v));
grd.addColorStop(1, hsv2hex(maxHue, s, v));
context.fillStyle = grd;
context.fill();
}
function getColourInterpolator(minVal, maxVal, minHue, maxHue) {
// copying Michael Taschler's code of interpolation
return function (val) {
// Give the values outside the limits the limit colours
if (val < minVal)
val = minVal;
else if (val > maxVal)
val = maxVal;
// 0.0 to 1.0 scale convertion
val -= minVal;
if ((maxVal - minVal) != 0) // avoid division by zero
val /= (maxVal - minVal);
else
val = 0;
var lowHue = minHue / 360.0;
var highHue = maxHue / 360.0;
var diffHue = highHue - lowHue;
var h = (lowHue + (val * diffHue)) * 360;
var s = 0.9;
var v = 0.9;
return hsv2hex(h, s, v);
}
}
function hsv2hex(h, s, v) {
// Hue stays the same
// Saturation is very different between the two color spaces
// If (2-s)*v < 1 set it to s*v/((2-s)*v)
// Otherwise s*v/(2-(2-s)*v)
// Conditional is not operating with hue, it is reassigned!
s = (s * v) / ((((2-s) * v) < 1) ? ((2-s) * v) : 2-((2-s) * v));
l = (2-s)*v/2; // Lightness is (2-s)*v/2
return d3.hsl(h, s, l).toString();
}
// All these convertXml() functions will be removed once the data will be returned in json
/*
function convertBuildsXml(xml) {
var elementsArray = [];
var elements = xml.documentElement.getElementsByTagName("Build");
for (var i=0; i<elements.length; i++) {
var build = {
Id: parseInt(elements[i].childNodes[0].childNodes[0].nodeValue),
CreatedOn: elements[i].childNodes[1].childNodes[0].nodeValue,
ModifiedOn: elements[i].childNodes[2].childNodes[0].nodeValue,
Identifier: parseFloat(elements[i].childNodes[3].childNodes[0].nodeValue),
HasAssetStats: elements[i].childNodes[4].childNodes[0].nodeValue,
HasProcessedStats: elements[i].childNodes[5].childNodes[0].nodeValue,
HasAutomatedEverythingStats: elements[i].childNodes[6].childNodes[0].nodeValue,
HasAutomatedMapOnlyStats: elements[i].childNodes[7].childNodes[0].nodeValue,
HasMagDemoStats: elements[i].childNodes[8].childNodes[0].nodeValue,
};
elementsArray.push(build);
}
return elementsArray;
}
*/
function convertResolutionsXml(xml) {
var elementsArray = [];
var elements = xml.documentElement.getElementsByTagName("ProcessedStatResolution");
for (var i=0; i<elements.length; i++) {
var resolution = {
Id: parseInt(elements[i].childNodes[0].childNodes[0].nodeValue),
CreatedOn: elements[i].childNodes[1].childNodes[0].nodeValue,
BlockSize: parseInt(elements[i].childNodes[2].childNodes[0].nodeValue),
};
elementsArray.push(resolution);
}
return elementsArray;
}
/*
// Use the generic ones instead
function convertPlatformsXml(xml) {
var elementsArray = [];
var elements = xml.documentElement.getElementsByTagName("Platform");
for (var i=0; i<elements.length; i++) {
var platform = {
Value: elements[i].getAttribute("Value"),
};
elementsArray.push(platform);
}
return elementsArray;
}
function convertGametypesXml(xml) {
var elementsArray = [];
var elements = xml.documentElement.getElementsByTagName("GameType");
for (var i=0; i<elements.length; i++) {
var gametype = {
Value: elements[i].getAttribute("Value"),
};
elementsArray.push(gametype);
}
return elementsArray;
}
*/
function convertBuildConfigsXml(xml) {
var elementsArray = [];
$(xml).find("BuildConfig").each(function(){
var buildConfig = {
Value: $(this).find("Value").text()
};
elementsArray.push(buildConfig);
});
return elementsArray;
}
function convertDrawListXml(xml) {
var elementsArray = [];
$(xml).find("DrawList").each(function(){
var element = {
Id: $(this).find("Id").text(),
CreatedOn: $(this).find("CreatedOn").text(),
ModifiedOn: $(this).find("ModifiedOn").text(),
Name: $(this).find("Name").text(),
Hash: $(this).find("Hash").text(),
};
elementsArray.push(element);
});
return elementsArray;
}
function convertDeathTelemetryStatXml(xml) {
var elementsArray = [];
// Using jquery to parse xml
$(xml).find("DeathTelemetryStat").each(function() {
var element = {
x: parseInt($(this).find("Location").attr("x")),
y: parseInt($(this).find("Location").attr("y")),
WeaponName: $(this).find("WeaponName").text(),
WeaponHash: $(this).find("WeaponHash").text(),
KillerIsPlayer: $(this).find("KillerIsPlayer").text(),
KillerIsLocalPlayer: $(this).find("KillerIsLocalPlayer").text(),
KillerInVehicle: $(this).find("KillerInVehicle").text(),
KillerRunning: $(this).find("KillerRunning").text(),
KillerSprinting: $(this).find("KillerSprinting").text(),
KillerCrouching: $(this).find("KillerCrouching").text(),
VictimIsPlayer: $(this).find("VictimIsPlayer").text(),
VictimIsLocalPlayer: $(this).find("VictimIsLocalPlayer").text(),
VictimInVehicle: $(this).find("VictimInVehicle").text(),
VictimRunning: $(this).find("VictimRunning").text(),
VictimSprinting: $(this).find("VictimSprinting").text(),
VictimCrouching: $(this).find("VictimCrouching").text(),
MissionName: $(this).find("MissionName").text(),
MissionStarted: $(this).find("MissionStarted").text(),
MissionEnded: $(this).find("MissionEnded").text(),
DeathTimestamp: $(this).find("DeathTimestamp").text(),
WantedLevel: $(this).find("WantedLevel").text(),
WantedLevelStarted: $(this).find("WantedLevelStarted").text(),
WantedLevelEnded: $(this).find("WantedLevelEnded").text(),
};
elementsArray.push(element);
});
return elementsArray;
}
//End of convertXml group of functions