Chart.JS插件,动画后绘制

约布莫德

我正在尝试编写一个chart.js(v.2.7)插件,以在散点图/折线图上显示误差线。我设法从图表中获得像素位置,并在画布上绘制误差线,但我无法把握时机。我希望它们在线动画后显示,然后如果数据集被隐藏->显示,则保持附加(并与之一起移动)。

我试过了:

  • afterDraw/ afterDataset(s)Draw/beforeDraw钩:误差棒是已经在线路动画之前积(如实施例中)。当隐藏->显示时,错误条就位。
  • afterRender/afterEvent钩子:在动画结束后绘制它们,但是每当隐藏数据集->显示时(在暂停之后),然后重新绘制它们
  • beforeRender /任何先前的钩子:不提供错误栏
  • setTimout() 在绘图功能上或在其中的各个位置上:什么都不做
  • sleep() 在绘制功能或其他位置之前:减慢整个动画的速度,但误差线不受影响。
  • 我找不到在动画后调用插件功能或通过 options.animation.onComplete

有没有一种方法可以使错误栏的行为如示例中所示,但是初始外观出现在线条动画之后(带有插件?)。

   var errorbarPlugin = {

	calcPoints: function(chartInstance, dataList){
		var ds = chartInstance.data.datasets
      var meta = chartInstance.getDatasetMeta(0)
        var yScale = chartInstance.scales[meta.yAxisID];
      var xScale = chartInstance.scales[meta.xAxisID];
      
      
		var yList = []; var xList = [];
			for(var i = 0; i < dataList.length; i++){
              
				var yValue = dataList[i].y
				var yPixel = yScale.getPixelForValue(yValue)
				yList.push(yPixel)
                
				var xValue = dataList[i].x
				var xPixel = xScale.getPixelForValue(xValue)
				xList.push(xPixel)
			}
      
		return {yList: yList, xList: xList}
	},

	calcErrorbars: function(chartInstance, ds_num){
		var ds = chartInstance.data.datasets
			var data_list = ds[ds_num].data
      
			var isHidden = ds[ds_num]._meta[Object.keys(chartInstance.data.datasets[ds_num]._meta)[0]].hidden;
			var yList = this.calcPoints(chartInstance, data_list).yList
			var xList = this.calcPoints(chartInstance, data_list).xList
			if(ds[ds_num].errors){
				var errors = ds[ds_num].errors
			} else {errors = 0}
      
		return [xList, yList, errors, isHidden]
	},


	drawErrorbars: function(chartInstance){
		var ctx = chartInstance.chart.ctx
		var ds = chartInstance.data.datasets
        		
		for(var ds_num = 0; ds_num < ds.length; ds_num++){
			var errCalc = this.calcErrorbars(chartInstance, ds_num)
			
			var isHidden = errCalc[3]
			var yList = errCalc[1]
			var xList = errCalc[0]
			var errors = errCalc[2]
			var errWidth = 3
			var capLen = 5

			if(!isHidden){
				for(var k = 0; k < xList.length; k++){
					
                  ctx.strokeStyle = "red"
				                  ctx.beginPath();
                  ctx.moveTo(xList[k], yList[k]-errors[k]);
                  ctx.lineTo(xList[k], yList[k]+errors[k]);
                  ctx.moveTo(xList[k]-capLen, yList[k]+errors[k]);
                  ctx.lineTo(xList[k]+capLen, yList[k]+errors[k]);
                  ctx.moveTo(xList[k]-capLen, yList[k]-errors[k]);
                  ctx.lineTo(xList[k]+capLen, yList[k]-errors[k]);
                  ctx.stroke()
					
				}
			}
		}
	},

	afterDatasetsDraw: function(chartInstance) {
		this.drawErrorbars(chartInstance)
	 },

}
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js"></script>



<script type="text/javascript" src="{% static 'js/charts/errorbarPlugin3.js' %}"></script>

	<div id="canvas-holder" class="col-sm-3">
		<canvas id="chart-gamma" width="200" height="200"/></canvas>
	</div>

<script defer>
var gammaChartData = {
	datasets: [
		{
		label: 'Red',
		data: [{x: 15, y: 30}, {x: 35, y: 17}, {x: 55, y: 37}, {x: 72, y: 45},],
		borderColor: "red",
		errors: [10, 28, 30, 34],
		},
	]
	}

var ctx_gamma = document.getElementById("chart-gamma").getContext("2d");

	window.onload = function() {
	var gamma_chart = new Chart(ctx_gamma, {
		type: 'scatter',
		data: gammaChartData,
		plugins: [errorbarPlugin],
		options: {showLines: true},
	});
};
</script>


</body>

</html>

编辑:通过删除格式和默认选项缩短了代码段

约布莫德

这是我想出的(下面的代码段)

误差条既可以固定在数据上,也可以独立显示,并在数据中隐藏/显示动画。

插件可以添加x或y轴错误,表示为条形(带/不带帽)或椭圆形/圆形(实心或透明)。

"use strict";
var errorbarPlugin = {
    afterDraw: function (chart) {
        var type = chart.config.type;
        var plugConfig = chart.config.options.errorbarPlugin;
        if (plugConfig) {
            if (plugConfig.showErrors) {
                var showErrors = plugConfig.showErrors;
            }
        }
        else
            showErrors = true;
        if (showErrors !== false) {
            if (["line", "scatter"].includes(type)) {
                errorbarPlugin.scatterErrorbars(chart);
            }
            else if (type == "bar") {
                console.log("Bar charts not supported yet");
            }
        }
    },
    scatterErrorbars: function (chart) {
        var ctx = chart.ctx;
        var plugConfig = chart.config.options.errorbarPlugin;
        chart.data.datasets.forEach(function (dataset, i) {
            var ds = dataset;
            var meta = chart.getDatasetMeta(i);
            var showErrors;
            (ds.showErrors === false) ? showErrors = false : showErrors = true;
            var errWidth;
            (ds.errWidth) ? errWidth = ds.errWidth : errWidth = 1;
            var showCap;
            (ds.showCap) ? showCap = ds.showCap : showCap = true;
            var capLen;
            (ds.capLen) ? capLen = ds.capLen : capLen = 3;
            var errStyle;
            (ds.errStyle) ? errStyle = ds.errStyle : errStyle = "T";
            var errFillColor;
            (ds.errFillColor) ? errFillColor = ds.errFillColor : errFillColor = "rgba(0,0,0,0)";
            if (!meta.hidden && showErrors) {
                meta.data.forEach(function (element, index) {
                    var x_point = element._model.x;
                    var y_point = element._model.y;
                    var errColor;
                    (ds.errColor) ? errColor = ds.errColor : errColor = element._view.borderColor;
                    var dataPoint = ds.data[index];
                    var yError;
                    var xError;
                    if (typeof (dataPoint) === "object" && 'r' in dataPoint) {
                        yError = dataPoint.r;
                    }
                    else if (ds.errors) {
                        yError = ds.errors[index];
                    }
                    else {
                        yError = null;
                    }
                    if (typeof (dataPoint) === "object" && dataPoint.e) {
                        xError = dataPoint.e;
                    }
                    else if (ds.xErrors) {
                        xError = ds.xErrors[index];
                    }
                    else {
                        xError = null;
                    }
                    var position = element.tooltipPosition();
                    if (errStyle == "circle") {
                        ctx.beginPath();
                        ctx.arc(position.x, position.y, yError, 0, 2 * Math.PI, false);
                        if (ds.hidden === true && meta.hidden === null) {
                            ctx.strokeStyle = "rgba(0,0,0,0)";
                            ctx.fillStyle = "rgba(0,0,0,0)";
                        }
                        else {
                            ctx.strokeStyle = errColor;
                            ctx.fillStyle = errFillColor;
                        }
                        console.log(meta.hidden);
                        ctx.fill();
                        ctx.stroke();
                    }
                    else if (errStyle == "oval" || errStyle == "ellipse") {
                        if (xError) {
                            var scaleFac = (xError) / yError;
                        }
                        else
                            scaleFac = 10 / yError;
                        ctx.beginPath();
                        ctx.save();
                        ctx.scale(scaleFac, 1);
                        ctx.arc(position.x / scaleFac, position.y, yError, 0, 2 * Math.PI, false);
                        ctx.restore();
                        if (ds.hidden === true && meta.hidden === null) {
                            ctx.strokeStyle = "rgba(0,0,0,0)";
                        }
                        else {
                            ctx.strokeStyle = errColor;
                        }
                        ctx.stroke();
                    }
                    else {
                        ctx.beginPath();
                        ctx.moveTo(position.x, position.y - yError);
                        ctx.lineTo(position.x, position.y + yError);
                        if (xError) {
                            ctx.moveTo(position.x - xError, position.y);
                            ctx.lineTo(position.x + xError, position.y);
                        }
                        if (ds.hidden === true && meta.hidden === null) {
                            ctx.strokeStyle = "rgba(0,0,0,0)";
                        }
                        else {
                            ctx.strokeStyle = errColor;
                        }
                        ctx.stroke();
                        if (showCap) {
                            ctx.beginPath();
                            ctx.moveTo(position.x - capLen, position.y - yError);
                            ctx.lineTo(position.x + capLen, position.y - yError);
                            ctx.moveTo(position.x - capLen, position.y + yError);
                            ctx.lineTo(position.x + capLen, position.y + yError);
                            if (xError) {
                                ctx.moveTo(position.x - xError, position.y - capLen);
                                ctx.lineTo(position.x - xError, position.y + capLen);
                                ctx.moveTo(position.x + xError, position.y - capLen);
                                ctx.lineTo(position.x + xError, position.y + capLen);
                            }
                            ctx.stroke();
                        }
                    }
                });
            }
        });
    }
};
<!DOCTYPE html>

<!--DOCTYPE html -->
<html>
<head>

<script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js'></script>



<body>
 
<div style = "position:relative;
    width:60%;"      >

	<div id="canvas-holder" class="col-sm-6">
		<canvas id="chart-gamma" width="500" height="500"/></canvas>
	</div>

		<div id="canvas-holderbf2" class="col-sm-6">
			<canvas id="chart-humid" width="500" height="500"/></canvas>
		</div>

<script defer>

Chart.defaults.global.legend.display = true
Chart.defaults.global.legend.position = 'right'
// Chart.defaults.global.legend.onHover = function(){}
// Chart.defaults.global.legend.onClick = function(){}
Chart.defaults.global.legend.labels.usePointStyle = true
Chart.defaults.global.legend.labels.fontsize = 12
Chart.defaults.global.legend.labels.padding = 10

var gammaChartData = {
	datasets: [
		{
		label: 'Eu',
		data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
		borderColor: "red",
		//fillColor: "pink",
		errors: [15, 20, 30, 12, 10, 10],
		xErrors: [3, 7, 16, 12, 12, 30, 10],
		//hidden: true,
		errColor: "blue",
		errStyle: "circle",
		errFillColor: "pink",
		hidden: true,
		errWidth: 2,
		showCap: true,
		capLen: 3,
		showErrors: true,
		},
		{
		label: 'Am',
		data: [{x: 15, y: 85, r: 14}, {x: 25, y: 37, r: 8}, {x: 62, y: 135, r: 44},],
		borderColor: "blue",
		errColor: "red",
		errStyle: "circle",
		showErrors: true,
		},
	]

	}
var options_gamma = {
	animation: {
		duration: 1000,
	},
	errorbarPlugin: {
					showErrors: true,
					marginsOfError: [100, 50, 10],
	},
	elements: {
		line: { fill: false,
				borderWidth: 1,
		},
		point: { radius: 0,
				pointStyle: 'circle',
				borderWidth: 1,
				hitRadius: 18, //size if should hover
				// hoverBorderWidth: 13,
				hoverRadius: 10, //size when hovered
		},
	},
	annotation: {
		annotations: [{
				id: 'h-line-01', // optional
				type: 'line',
				mode: 'horizontal',
				scaleID: 'y-axis-0',
				value: '125',
				borderColor: 'red',
				borderDash: [2, 2],
				borderWidth: 2,
				label: {
						enabled: true,
						backgroundColor: 'rgba(255,255,255,1)', // Background color of label, default below
						//fontFamily: "sans-serif", // Font family of text, inherits from global
						fontStyle: "normal", // Font style of text, default "bold"
						fontSize: 12, // Font size of text, inherits from global
						fontColor: "red",// Font color of text, default below
						xPadding: 5,// Padding of label to add top/bottom, default below
						yPadding: 5,// Radius of label rectangle, default below
						cornerRadius: 10, // Anchor position of label on line, can be one of: top, bottom, left, right, center. Default below.
						position: "left",	// Adjustment along x-axis (left-right) of label relative to above number (can be negative)
											// For horizontal lines positioned left or right, negative values move the label toward the edge, and negative values toward the center.
						xAdjust: 290,			// Adjustment along y-axis (top-bottom) of label relative to above number (can be negative)
											// For vertical lines positioned top or bottom, negative values move the label toward the edge, and negative values toward the center.
						yAdjust: 0,			// Whether the label is enabled and should be displayed
							// Text to display in label - default is null
						content: "Max"
					},
					onClick: function(e) { // Fires when the user clicks this annotation on the chart (be sure to enable the event in the events array below).
					}
		}],
	},
	responsive: true,
	showLines: true,
	hoverMode: 'single', // should always use single for a scatter chart
	legend: {},
	scales: {
		yAxes: [{
			display: true,
			position: 'left',
			id: 'y-axis-0',
			ticks: {min: 0, 	//beginAtZero:true,
					max: 200,
					//display: true,
					//fontColor: "black"
			},
			scaleLabel: {display: true,	labelString: 'Number'},
			gridLines: {color: "black",
						//display: true,
						drawOnChartArea: false,
						zeroLineColor: "black",
						//drawTicks: true,
			},
		}],
		xAxes: [{
			display: true,
			type: 'linear',
			id: 'x-axis-0',
			position: 'bottom',
			ticks: {min: 0,
					max: 100,
					//display: true,
					//fontColor: "black",
			},
			scaleLabel: {display: true,	labelString: 'Volume'},
			gridLines: {color: "black",
						zeroLineColor: "black",
						drawOnChartArea: false,
			},
		}],
	},
}
var ctx_gamma = document.getElementById("chart-gamma").getContext("2d");

var humidChartData = {
	datasets: [
		{
		label: 'B errors',
		data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
		borderColor: "green",
		errors: [15, 20, 30, 12, 10, 10],
		xErrors: [3, 7, 16, 12, 12, 30, 10],
		errStyle: "oval",
		showLine: false,
		errColor: "border",
		//pointBackgroundColor: "white",
		//pointBordercolor: "white",
		backgroundColor: "rgba(0,0,0,0)",
		hidden: true,
		errWidth: 2,
		showCap: true,
		capLen: 3,
		radius: 0,
		showErrors: true,
		},
		{
			label: 'B trend',
			data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
			borderColor: "green",
			errors: [15, 20, 30, 12, 10, 10],
			xErrors: [3, 7, 16, 12, 12, 30, 10],
			pointStyle: "line",
			showErrors: false,
		radius: 0,
		},
		{
			label: 'B data',
			data: [{x: 5, y: 45}, {x: 10, y: 100}, {x: 25, y: 120}, {x: 50, y: 125}, {x: 100, y: 150}, {x: 120, y: 250},],
			borderColor: "green",
			backgroundColor: "green",
			errors: [15, 20, 30, 12, 10, 10],
			xErrors: [3, 7, 16, 12, 12, 30, 10],
			showErrors: false,
			showLine: false,
		},
		{
		label: '',
		data: [],
		borderColor: "rgba(0,0,0,0)",
		backgroundColor: "rgba(0,0,0,0)",
		},
		{
		label: 'C data',
		data: [{x: 15, y: 85, r: 14}, {x: 25, y: 37, r: 8}, {x: 62, y: 135, r: 44},],
		borderColor: "blue",
		backgroundColor: "rgba(0,0,0,0)",
        xErrors: [3, 7, 16, 12, 12, 30, 10],
		showLine: true,
		showErrors: true,
		},
	]

	}
var options_humid = {
	hoverMode: 'single',
	elements: {
		line: { fill: false,
				borderWidth: 2,
		},
		point: { radius: 3,
				pointStyle: 'circle',
				borderWidth: 1,
				hitRadius: 0,
				// hoverBorderWidth: 13,
				hoverRadius: 9,
		},
	},
	responsive: true,
	showLines: true,
	hoverMode: 'single', // should always use single for a scatter chart
	legend: {
		labels: {
			usePointStyle: true,
			// generateLabels: function() {	}
		}
	},
		scales: {
			yAxes: [{
				display: true,
				position: 'left',
				id: 'y-axis-0',
				ticks: {min: 0, 	//beginAtZero:true,
						max: 300 },
				scaleLabel: {display: true,	labelString: 'Number'},
				gridLines: {zeroLineColor: "black", },
			}],
			xAxes: [{
				display: true,
				type: 'linear',
				id: 'x-axis-0',
				position: 'bottom',
				ticks: {min: 0,
						max: 200 },
				scaleLabel: {display: true,	labelString: 'Month'},
				gridLines: {zeroLineColor: "black", },
			}],
		},
}
var ctx_humid = document.getElementById("chart-humid").getContext("2d");

window.onload = function() {
	var humidChart = new Chart(ctx_humid, {
		type: 'line',
		data: humidChartData,
		plugins: [errorbarPlugin],
		options: options_humid,
	});

	var gamma_chart = new Chart(ctx_gamma, {
		type: 'scatter',
		data: gammaChartData,
		plugins: [errorbarPlugin],
		options: options_gamma,
	});
};

</script>





</div>

</body>
</html>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章