// save the original line element so we can still call it's
// draw method after we build the linear gradient
var origLineElement = Chart.elements.Line;
// define a new line draw method so that we can build a linear gradient
// based on the position of each point
Chart.elements.Line = Chart.Element.extend({
draw: function() {
var vm = this._view;
var backgroundColors = this._chart.controller.data.datasets[this._datasetIndex].backgroundColor;
var points = this._children;
var ctx = this._chart.ctx;
var minX = points[0]._model.x;
var maxX = points[points.length - 1]._model.x;
var linearGradient = ctx.createLinearGradient(minX, 0, maxX, 0);
// iterate over each point to build the gradient
points.forEach(function(point, i) {
// `addColorStop` expects a number between 0 and 1, so we
// have to normalize the x position of each point between 0 and 1
// and round to make sure the positioning isn't too percise
// (otherwise it won't line up with the point position)
var colorStopPosition = roundNumber((point._model.x - minX) / (maxX - minX), 2);
// special case for the first color stop
if (i === 0) {
linearGradient.addColorStop(0, backgroundColors[i]);
} else {
// only add a color stop if the color is different
if (backgroundColors[i] !== backgroundColors[i-1]) {
// add a color stop for the prev color and for the new color at the same location
// this gives a solid color gradient instead of a gradient that fades to the next color
linearGradient.addColorStop(colorStopPosition, backgroundColors[i - 1]);
linearGradient.addColorStop(colorStopPosition, backgroundColors[i]);
}
}
});
// save the linear gradient in background color property
// since this is what is used for ctx.fillStyle when the fill is rendered
vm.backgroundColor = linearGradient;
// now draw the lines (using the original draw method)
origLineElement.prototype.draw.apply(this);
}
});
// we have to overwrite the datasetElementType property in the line controller
// because it is set before we can extend the line element (this ensures that
// the line element used by the chart is the one that we extended above)
Chart.controllers.line = Chart.controllers.line.extend({
datasetElementType: Chart.elements.Line,
});
// save the original line element so we can still call it's
// draw method after we build the linear gradient
var origLineElement = Chart.elements.Line;
// define a new line draw method so that we can build a linear gradient
// based on the position of each point
Chart.elements.Line = Chart.Element.extend({
draw: function() {
var vm = this._view;
var backgroundColors = this._chart.controller.data.datasets[this._datasetIndex].backgroundColor;
var points = this._children;
var ctx = this._chart.ctx;
var minX = points[0]._model.x;
var maxX = points[points.length - 1]._model.x;
var linearGradient = ctx.createLinearGradient(minX, 0, maxX, 0);
// if not a single color
if( typeof backgroundColors != 'string' ){
// but is array of colors
if( typeof backgroundColors[0] === 'string' ) {
// iterate over each point to build the gradient
points.forEach(function(point, i) { // start original code
// `addColorStop` expects a number between 0 and 1, so we
// have to normalize the x position of each point between 0 and 1
// and round to make sure the positioning isn't too percise
// (otherwise it won't line up with the point position)
var colorStopPosition = self.roundNumber((point._model.x - minX) / (maxX - minX), 2);
// special case for the first color stop
if (i === 0) {
linearGradient.addColorStop(0, backgroundColors[i]);
} else {
// only add a color stop if the color is different
if ( backgroundColors[i] !== backgroundColors[i-1]) {
// add a color stop for the prev color and for the new color at the same location
// this gives a solid color gradient instead of a gradient that fades to the next color
linearGradient.addColorStop(colorStopPosition, backgroundColors[i - 1]);
linearGradient.addColorStop(colorStopPosition, backgroundColors[i]);
}
}
}); // end original code
} // end of if for color array
// must be a gradient fence position list
else {
// loop thru the fence positions
backgroundColors.forEach(function(fencePosition){
var colorStopPosition = self.roundNumber(fencePosition.offset / points.length, 2);
linearGradient.addColorStop(colorStopPosition,fencePosition.color)
});
} // end of block for handling color space edges
// save the linear gradient in background color property
// since this is what is used for ctx.fillStyle when the fill is rendered
vm.backgroundColor = linearGradient;
} // end of if for just one color
// now draw the lines (using the original draw method)
origLineElement.prototype.draw.apply(this);
}
4条答案
按热度按时间xxslljrj1#
不幸的是,你不能用当前的图表实现这一点。js配置选项。原因是折线图
backgroundColor
选项(控制折线图填充颜色的选项)仅接受单个值。在浏览了当前的图表后。js 2.5源码,我发现可以扩展线元素的
draw()
方法和力图。js使用canvas线性渐变填充(而不仅仅是一种颜色)。通过一点数学运算,我们可以将每个点的x位置转换为线性渐变颜色停止位置并构建渐变。有了这个增强功能,您现在可以将颜色数组传递给折线图
backgroundColor
选项,以实现不同颜色的填充区域。下面是一个结果图表的示例。以下是如何实际做到这一点(底部有一个工作示例)
首先,我们必须扩展
Chart.elements.Line
并覆盖它的draw()
方法,以便我们可以基于每个点的位置构建线性梯度,将其用作线填充,然后绘制线。然后,我们还必须扩展折线图,以确保图表使用的line元素是我们上面扩展的那个元素(因为这个属性在加载时已经设置了)
完成这些之后,我们现在可以将颜色数组传递给折线图
backgroundColor
属性(而不是只有一个值)来控制线条填充。下面是一个codepen example,它演示了所有已经讨论过的内容。
注意事项:
pu82cl6c2#
如果你想用angular2和ng 2-charts来实现这个功能,也许有一种不那么“黑客”的方法来做到这一点,但这就是我如何应用Jordan的代码来实现它的工作:
1.降级ng 2-chart对Chart的依赖性。js从2.7X至2.5。
1.在node_modules/chart中。js/src/charts:- 把Jordan的代码加到Chartline.js(在导出中)。线函数
1.重建图表。js/dist:- run npm install
1.运行gulp构建
1.如果您从 www.example.com 。io,我相信Karma可能有一个旧版本的socket。你可以升级到2。0.
不管怎样,这对我很有效。它没有完全测试,它绝对是一个“黑客”,但我不想学习图表。js 2.7来弄清楚为什么Jordan的代码不能使用它。这绝对是更“正确”的方式。我认为它应该被集成为一个“插件”。
bf1o4zei3#
我决定做chartjs 2.5方法,但使用上面的扩展,而不是修改chartjs代码本身。.
我必须在一些性能优化上下功夫,因为我的图表有超过4000个值。获得用正确的值(稀疏的替代颜色,可能用于4000个值中的200)构建的颜色阵列,然后让扩展读取它以构建线性梯度是非常耗时的。埋树莓PI我正在使用的图表显示系统。
我最终决定,为了减少处理时间,我需要消除对点列表的任何额外处理。、采集、生成颜色数组、绘制线性梯度图。..
所以,现在我创建线性梯度边缘,因为我去通过数据(所有在一个通道)。梯度是具有从数据阵列的开始的偏移的结构的阵列,并且要应用于该边缘的颜色基本上做原始扩展所做的事情。.因此,将800个点减少到40个边。或800个点到1个边(开始)。..
下面是我更新扩展函数。.我的应用程序有所有三种颜色类型的图表。单一固定、颜色数组和边数组。.上面所有其他例程都没有改变
nlejzf6q4#
到目前为止,这个问题可以通过segment的backgroundColor轻松解决: