Widget:NVD3JS

From Granblue Fantasy Wiki
Revision as of 04:11, 14 December 2019 by Hal (talk | contribs)
Jump to navigation Jump to search
<script type="application/javascript">
let processChartElement = function(element) {
	let series = [], errors = [];
	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",
		};
		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)
			;
			chart.xAxis
				.showMaxMin(true)
				.tickFormat(d3.format(xTickFormat))
			;
			chart.yAxis
				.showMaxMin(true)
				.tickFormat(d3.format(yTickFormat))
			;
			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>