Widget:NVD3Test
Jump to navigation
Jump to search
<script type="application/javascript">
let processChartElement = function(element) {
let series = [], errors = [];
let formatDaysTime = (minutesPassed) => {
var t = minutesPassed % 1440;
var d = Math.floor(minutesPassed / 1440) + 1;
var m = Math.floor(t%60)
m = m < 10 ? "0" + m.toString() : m
if (t == 0) { d = d-1; t = 1440; }
return "Day " + d + ", " + Math.floor(t/60) + ":" + m;
}
let convertTeamRaidTime = (s) => {
return formatDaysTime(1160 + (s/60));
}
for (let s of element.querySelectorAll('[data-series-label]')) {
let sd = {
key: s.dataset.seriesLabel || ('Unlabelled[' + series.length + ']'),
values: [],
color: s.dataset.seriesColor,
area: s.dataset.seriesArea == "yes",
grid: {
x: null,
y: null
}
};
if (s.dataset.seriesX && s.dataset.seriesY) {
let xv = s.dataset.seriesX.match(/\-?(?:\d+(?:\.\d+)?|\.\d+)/g);
let yv = s.dataset.seriesY.match(/\-?(?:\d+(?:\.\d+)?|\.\d+)/g);
if (xv && yv && xv.length == yv.length) {
for (let i = 0; i < xv.length; i++) {
sd.values.push({
x: Number.parseFloat(xv[i]),
y: Number.parseFloat(yv[i]),
});
}
}
} else if (s.dataset.seriesLinearInterpolation) {
let prep = [];
for (let x of s.dataset.seriesLinearInterpolation.match(/\-?(?:\d+(?:\.\d+)?|\.\d+)/g)) {
x = Number.parseFloat(x);
if (prep.length == 0 || prep[prep.length-1].length == 2)
prep.push([x]);
else
prep[prep.length-1].push(x)
}
if (prep.length && prep[prep.length-1].length != 2) prep.pop();
prep.sort(function(a,b) { return a[0] == b[0] ? 0 : (a[0] < b[0] ? -1 : 1); });
sd.values.push({x: prep[0][0], y: prep[0][1]});
let stepSize = s.dataset.seriesInterpolationStep ? Number.parseFloat(s.dataset.seriesInterpolationStep) : 1;
if (isNaN(stepSize) || stepSize < 0.5) stepSize = 1;
for (let i = 1; i < prep.length; i++) {
let x0 = sd.values[sd.values.length-1].x, x1 = prep[i][0];
let y0 = sd.values[sd.values.length-1].y, y1 = prep[i][1];
let dy = (y1-y0)/(x1-x0);
for (let j=stepSize; (x0+j) < x1; j += stepSize) {
sd.values.push({x: x0+j, y: y0+j*dy});
}
sd.values.push({x: x1, y: y1});
}
}
if (sd.values.length) {
series.push(sd);
} else {
errors.push("Series contains invalid or incomplete data - " + sd.key);
}
}
if (series.length) {
let firstPoint = series[0].values[0];
let yMin = firstPoint.y, yMax = firstPoint.y, xMin = firstPoint.x, xMax = firstPoint.x;
for (let i = series.length; i-->0;) {
for (let j = series[i].values.length; j-->0;) {
let y = series[i].values[j].y;
if (y > yMax)
yMax = y;
else if (yMin > y)
yMin = y;
}
if (xMin > series[i].values[0].x)
xMin = series[i].values[0].x;
let lp = series[i].values[series[i].values.length-1];
if (lp.x > xMax)
xMax = lp.x;
}
while (element.firstChild)
element.removeChild(element.firstChild);
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.style.width = element.dataset.chartWidth || (element.clientWidth + 'px');
svg.style.height = element.dataset.chartHeight || (element.clientHeight + 'px');
element.appendChild(svg);
let yAxisWidth = element.dataset.yAxisWidth ? Number.parseInt(element.dataset.yAxisWidth) : 0;
let yTickFormat = Math.max(yMax, Math.abs(yMin)) <= 200 ? ',.02f' : ',s';
let xTickFormat = ',r';
if (element.dataset.yNumberFormat) yTickFormat = element.dataset.yNumberFormat;
if (element.dataset.xNumberFormat) xTickFormat = element.dataset.xNumberFormat;
nv.addGraph(function() {
var chart = nv.models.lineChart()
.useInteractiveGuideline(true)
.showYAxis(true)
.showXAxis(true)
;
var xF, yF;
switch (xTickFormat) {
case '': xF = d3.format(',r'); break;
case 'teamraid': xF = convertTeamRaidTime; break;
case 'daystime': xF = formatDaysTime; break;
default: xF = d3.format(xTickFormat); break;
}
switch (yTickFormat) {
case '': yF = d3.format(',.02f'); break;
case 'teamraid': yF = convertTeamRaidTime; break;
case 'daystime': yF = formatDaysTime; break;
default: yF = d3.format(yTickFormat); break;
}
chart.xAxis
.showMaxMin(true)
.tickFormat(xF)
// .tickValues([-69600, 103200, 214800,276000,362400,448800,535200])
;
chart.yAxis
.showMaxMin(true)
.tickFormat(yF)
;
// Gridlines at custom positions
let g = [], gx = [], gy = [];
if (element.dataset.xGrid) {
g = element.dataset.xGrid.match(/\-?(?:\d+(?:\.\d+)?|\.\d+)/g);
for (let i = 0; i < g.length; i++) {
gx.push(Number.parseFloat(g[i]));
}
if (gx.length > 0) {
chart.xAxis.tickValues(gx);
}
}
if (element.dataset.yGrid) {
g = element.dataset.yGrid.match(/\-?(?:\d+(?:\.\d+)?|\.\d+)/g);
for (let i = 0; i < g.length; i++) {
gy.push(Number.parseFloat(g[i]));
}
if (gy.length > 0) {
chart.yAxis.tickValues(gy);
}
}
if (yAxisWidth && yAxisWidth > 0)
chart.margin({left: yAxisWidth});
if (yAxisWidth && yAxisWidth > 70)
chart.yAxis.axisLabelDistance(yAxisWidth-70);
if (element.dataset.axisLabelX)
chart.xAxis.axisLabel(element.dataset.axisLabelX);
if (element.dataset.axisLabelY)
chart.yAxis.axisLabel(element.dataset.axisLabelY);
d3.select(svg)
.datum(series)
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
} else {
errors.push("Chart contains no usable series.");
}
if (errors.length) {
let es = document.createElement('span');
for (let i = 0; i < errors.length; i++) {
if (i) es.appendChild(document.createElement('br'));
es.appendChild(document.createTextNode(errors[i]));
}
es.className = "error-message";
element.appendChild(es);
}
};
if (document.querySelector('[data-nvd3-chart]'))
RLQ.push(['jquery', function() {
mw.loader.using('ext.cargo.nvd3', function(require) {
for (var e of document.querySelectorAll('[data-nvd3-chart]')) {
processChartElement(e);
}
});
}]);
</script>