Bug 967378 - Part 1: Network statistics: don't rely on parseFloat to deal with numbers in the charts, r=rcampbell

This commit is contained in:
Victor Porof 2014-02-04 16:57:08 +02:00
parent 9ca9b2f699
commit 0a8be38c65
5 changed files with 96 additions and 61 deletions

View File

@ -2343,13 +2343,9 @@ PerformanceStatisticsView.prototype = {
id: "#primed-cache-chart",
title: "charts.cacheEnabled",
data: this._sanitizeChartDataSource(aItems),
sorted: true,
totals: {
size: L10N.getStr("charts.totalSize"),
time: L10N.getStr("charts.totalTime2"),
cached: L10N.getStr("charts.totalCached"),
count: L10N.getStr("charts.totalCount")
}
strings: this._commonChartStrings,
totals: this._commonChartTotals,
sorted: true
});
window.emit(EVENTS.PRIMED_CACHE_CHART_DISPLAYED);
},
@ -2365,26 +2361,53 @@ PerformanceStatisticsView.prototype = {
id: "#empty-cache-chart",
title: "charts.cacheDisabled",
data: this._sanitizeChartDataSource(aItems, true),
sorted: true,
totals: {
size: L10N.getStr("charts.totalSize"),
time: L10N.getStr("charts.totalTime2"),
cached: L10N.getStr("charts.totalCached"),
count: L10N.getStr("charts.totalCount")
}
strings: this._commonChartStrings,
totals: this._commonChartTotals,
sorted: true
});
window.emit(EVENTS.EMPTY_CACHE_CHART_DISPLAYED);
},
/**
* Common stringifier predicates used for items and totals in both the
* "primed" and "empty" cache charts.
*/
_commonChartStrings: {
size: value => {
let string = L10N.numberWithDecimals(value / 1024, CONTENT_SIZE_DECIMALS);
return L10N.getFormatStr("charts.sizeKB", string);
},
time: value => {
let string = L10N.numberWithDecimals(value / 1000, REQUEST_TIME_DECIMALS);
return L10N.getFormatStr("charts.totalS", string);
}
},
_commonChartTotals: {
size: total => {
let string = L10N.numberWithDecimals(total / 1024, CONTENT_SIZE_DECIMALS);
return L10N.getFormatStr("charts.totalSize", string);
},
time: total => {
let string = L10N.numberWithDecimals(total / 1000, REQUEST_TIME_DECIMALS);
return L10N.getFormatStr("charts.totalTime2", string);
},
cached: total => {
return L10N.getFormatStr("charts.totalCached", total);
},
count: total => {
return L10N.getFormatStr("charts.totalCount", total);
}
},
/**
* Adds a specific chart to this container.
*
* @param object
* An object containing all or some the following properties:
* - id: either "#primed-cache-chart" or "#empty-cache-chart"
* - title/data/sorted/totals: @see Chart.jsm for details
* - title/data/strings/totals/sorted: @see Chart.jsm for details
*/
_createChart: function({ id, title, data, sorted, totals }) {
_createChart: function({ id, title, data, strings, totals, sorted }) {
let container = $(id);
// Nuke all existing charts of the specified type.
@ -2397,8 +2420,9 @@ PerformanceStatisticsView.prototype = {
diameter: NETWORK_ANALYSIS_PIE_CHART_DIAMETER,
title: L10N.getStr(title),
data: data,
sorted: sorted,
totals: totals
strings: strings,
totals: totals,
sorted: sorted
});
chart.on("click", (_, item) => {
@ -2463,13 +2487,6 @@ PerformanceStatisticsView.prototype = {
data[type].count++;
}
for (let chartItem of data) {
let size = L10N.numberWithDecimals(chartItem.size / 1024, CONTENT_SIZE_DECIMALS);
let time = L10N.numberWithDecimals(chartItem.time / 1000, REQUEST_TIME_DECIMALS);
chartItem.size = L10N.getFormatStr("charts.sizeKB", size);
chartItem.time = L10N.getFormatStr("charts.totalS", time);
}
return data.filter(e => e.count > 0);
},
};

View File

@ -9,24 +9,27 @@ function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, Chart } = aMonitor.panelWin;
let { document, L10N, Chart } = aMonitor.panelWin;
let container = document.createElement("box");
let table = Chart.Table(document, {
title: "Table title",
data: [{
label1: 1,
label2: "11.1foo"
label2: 11.1
}, {
label1: 2,
label2: "12.2bar"
label2: 12.2
}, {
label1: 3,
label2: "13.3baz"
label2: 13.3
}],
strings: {
label2: (value, index) => value + ["foo", "bar", "baz"][index]
},
totals: {
label1: "Hello %S",
label2: "World %S"
label1: value => "Hello " + L10N.numberWithDecimals(value, 2),
label2: value => "World " + L10N.numberWithDecimals(value, 2)
}
});

View File

@ -17,8 +17,8 @@ function test() {
title: "Table title",
data: null,
totals: {
label1: "Hello %S",
label2: "World %S"
label1: value => "Hello " + L10N.numberWithDecimals(value, 2),
label2: value => "World " + L10N.numberWithDecimals(value, 2)
}
});

View File

@ -9,24 +9,27 @@ function test() {
initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, Chart } = aMonitor.panelWin;
let { document, L10N, Chart } = aMonitor.panelWin;
let container = document.createElement("box");
let chart = Chart.PieTable(document, {
title: "Table title",
data: [{
size: 1,
label: "11.1foo"
label: 11.1
}, {
size: 2,
label: "12.2bar"
label: 12.2
}, {
size: 3,
label: "13.3baz"
label: 13.3
}],
strings: {
label2: (value, index) => value + ["foo", "bar", "baz"][index]
},
totals: {
size: "Hello %S",
label: "World %S"
size: value => "Hello " + L10N.numberWithDecimals(value, 2),
label: value => "World " + L10N.numberWithDecimals(value, 2)
}
});

View File

@ -96,18 +96,19 @@ function PieTableChart(node, pie, table) {
* - data: an array of items used to display each slice in the pie
* and each row in the table;
* @see `createPieChart` and `createTableChart` for details.
* - strings: @see `createTableChart` for details.
* - totals: @see `createTableChart` for details.
* - sorted: a flag specifying if the `data` should be sorted
* ascending by `size`.
* - totals: @see `createTableChart` for details.
* @return PieTableChart
* A pie+table chart proxy instance, which emits the following events:
* - "mouseenter", when the mouse enters a slice or a row
* - "mouseleave", when the mouse leaves a slice or a row
* - "click", when the mouse enters a slice or a row
*/
function createPieTableChart(document, { sorted, title, diameter, data, totals }) {
function createPieTableChart(document, { title, diameter, data, strings, totals, sorted }) {
if (sorted) {
data = data.slice().sort((a, b) => +(parseFloat(a.size) < parseFloat(b.size)));
data = data.slice().sort((a, b) => +(a.size < b.size));
}
let pie = Chart.Pie(document, {
@ -118,6 +119,7 @@ function createPieTableChart(document, { sorted, title, diameter, data, totals }
let table = Chart.Table(document, {
title: title,
data: data,
strings: strings,
totals: totals
});
@ -202,7 +204,7 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
let isPlaceholder = false;
// Filter out very small sizes, as they'll just render invisible slices.
data = data ? data.filter(e => parseFloat(e.size) > EPSILON) : null;
data = data ? data.filter(e => e.size > EPSILON) : null;
// If there's no data available, display an empty placeholder.
if (!data || !data.length) {
@ -222,10 +224,10 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
let proxy = new PieChart(container);
let total = data.reduce((acc, e) => acc + parseFloat(e.size), 0);
let angles = data.map(e => parseFloat(e.size) / total * (TAU - EPSILON));
let largest = data.reduce((a, b) => parseFloat(a.size) > parseFloat(b.size) ? a : b);
let smallest = data.reduce((a, b) => parseFloat(a.size) < parseFloat(b.size) ? a : b);
let total = data.reduce((acc, e) => acc + e.size, 0);
let angles = data.map(e => e.size / total * (TAU - EPSILON));
let largest = data.reduce((a, b) => a.size > b.size ? a : b);
let smallest = data.reduce((a, b) => a.size < b.size ? a : b);
let textDistance = radius / NAMED_SLICE_TEXT_DISTANCE_RATIO;
let translateDistance = radius / HOVERED_SLICE_TRANSLATE_DISTANCE_RATIO;
@ -307,19 +309,25 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
* should be objects representing columns, for which the
* properties' values will be displayed in each cell of a row.
* e.g: [{
* size: 1,
* label2: "1foo",
* label3: "2yolo"
* label1: 1,
* label2: 3,
* label3: "foo"
* }, {
* size: 2,
* label2: "3bar",
* label3: "4swag"
* label1: 4,
* label2: 6,
* label3: "bar
* }];
* - strings: an object specifying for which rows in the `data` array
* their cell values should be stringified and localized
* based on a predicate function;
* e.g: {
* label1: value => l10n.getFormatStr("...", value)
* }
* - totals: an object specifying for which rows in the `data` array
* the sum of their cells is to be displayed in the chart;
* e.g: {
* label1: "Total size: %S",
* label3: "Total lolz: %S"
* label1: total => l10n.getFormatStr("...", total), // 5
* label2: total => l10n.getFormatStr("...", total), // 9
* }
* @return TableChart
* A table chart proxy instance, which emits the following events:
@ -327,7 +335,9 @@ function createPieChart(document, { data, width, height, centerX, centerY, radiu
* - "mouseleave", when the mouse leaves a row
* - "click", when the mouse clicks a row
*/
function createTableChart(document, { data, totals, title }) {
function createTableChart(document, { title, data, strings, totals }) {
strings = strings || {};
totals = totals || {};
let isPlaceholder = false;
// If there's no data available, display an empty placeholder.
@ -365,10 +375,12 @@ function createTableChart(document, { data, totals, title }) {
rowNode.appendChild(boxNode);
for (let [key, value] in Iterator(rowInfo)) {
let index = data.indexOf(rowInfo);
let stringified = strings[key] ? strings[key](value, index) : value;
let labelNode = document.createElement("label");
labelNode.className = "plain table-chart-row-label";
labelNode.setAttribute("name", key);
labelNode.setAttribute("value", value);
labelNode.setAttribute("value", stringified);
rowNode.appendChild(labelNode);
}
@ -380,13 +392,13 @@ function createTableChart(document, { data, totals, title }) {
let totalsNode = document.createElement("vbox");
totalsNode.className = "table-chart-totals";
for (let [key, value] in Iterator(totals || {})) {
let total = data.reduce((acc, e) => acc + parseFloat(e[key]), 0);
let formatted = !isNaN(total) ? L10N.numberWithDecimals(total, 2) : 0;
for (let [key, value] in Iterator(totals)) {
let total = data.reduce((acc, e) => acc + e[key], 0);
let stringified = totals[key] ? totals[key](total || 0) : total;
let labelNode = document.createElement("label");
labelNode.className = "plain table-chart-summary-label";
labelNode.setAttribute("name", key);
labelNode.setAttribute("value", value.replace("%S", formatted));
labelNode.setAttribute("value", stringified);
totalsNode.appendChild(labelNode);
}