我已经使用plotOptions.zones在Highcharts中成功创建了一个具有统一阈值的面积样条图。如果值超过阈值 (100),则阈值以上的区域将显示为绿色。如果该值低于阈值,则该值和阈值之间的下方区域将显示为红色。
const series = ...;
const categories = ...;
const plotOptions = {
series: {
threshold: 100,
zones: [
{
value: 100,
color: 'red'
},{
color: 'green'
}
],
marker: {
lineWidth: 2,
lineColor: 'blue'
}
}
};
Highcharts.chart('container', {
chart: {
type: 'areaspline'
},
xAxis: {
categories: categories
},
plotOptions: plotOptions,
series: series
});
但是,我需要创建一个“方差图”,其中阈值可以沿 x 轴逐点变化。我已尝试使用以下代码为plotOptions生成区域,但它没有生成我需要的内容。 (我相信区域应该按照阈值增加的顺序来定义。)我如何通过配置 Highcharts API 来实现这一点,或者我需要创建一个扩展?
const data = [
{ value: 29.9, threshold: 50 },
{ value: 71.5, threshold: 60 },
{ value: 106.4, threshold: 70 },
{ value: 129.2, threshold: 80 },
{ value: 144.0, threshold: 90 },
{ value: 176.0, threshold: 100 },
{ value: 135.6, threshold: 110 },
{ value: 148.5, threshold: 120 },
{ value: 216.4, threshold: 130 },
{ value: 194.1, threshold: 140 },
{ value: 95.6, threshold: 150 },
{ value: 54.4, threshold: 160 }
];
const series = [{
data: data.map(obj => obj.value)
}];
const plotOptions = createPlotOptions(data);
// Update the thresholds dynamically
function createPlotOptions(data) {
return {
areaspline: {
zones: data.map(function(d) {
return {
value: d.threshold,
color: (d.value < d.threshold) ? 'red' : 'green'
};
})
}
};
}
Highcharts.chart('container', {
chart: {
type: 'areaspline'
},
xAxis: {
categories: categories
},
plotOptions: plotOptions,
series: series
});
我想出了一个使用堆叠样条图的解决方案,通过创建一个透明的“基础”系列来抵消目标(阈值)的值与系列中每个点的“实际”测量值。
let data = [
{ value: 70, threshold: 50 },
{ value: 71.5, threshold: 30 },
{ value: 50, threshold: 70 },
{ value: 129.2, threshold: 80 },
{ value: 95, threshold: 90 },
{ value: 120, threshold: 70 },
{ value: 115, threshold: 90 },
{ value: 80, threshold: 115 },
{ value: 180, threshold: 65 },
{ value: 150, threshold: 80 },
{ value: 95.6, threshold: 110 },
{ value: 54.4, threshold: 100 }
];
for (let i = 0; i < data.length; i++) {
let obj = data[i];
if (obj.value > obj.threshold) {
obj.above = obj.value - obj.threshold;
obj.below = 0;
obj.base = obj.threshold;
} else {
obj.above = 0
obj.below = obj.threshold - obj.value;
// offset the base below the measured value
obj.base = obj.value - (obj.threshold - obj.value);
}
data[i] = obj;
}
const series = [
{
name: 'Above',
type: 'areaspline',
data: data.map(obj => obj.above),
linkedTo: 'actual',
color: 'rgba(0,128,0,1)'
},
{
name: 'Below',
type: 'areaspline',
data: data.map(obj => obj.below),
linkedTo: 'actual',
color: 'rgba(255,0,0,1)'
},
{
name: 'Base',
type: 'areaspline',
data: data.map(obj => obj.base),
linkedTo: 'actual',
fillOpacity: 0,
},
{
name: 'Actual',
id: 'actual',
type: 'spline',
lineWidth: 2,
zIndex: 1,
color: 'yellow',
data: data.map(obj => obj.value)
},
{
name: 'Goal',
id: 'goal',
type: 'spline',
dashStyle: 'longdash',
zIndex: 2,
data: data.map(obj => obj.threshold)
}];
Highcharts.chart('container', {
title: {
text: 'Variance Chart'
},
tooltip: {
shared: true,
formatter: function() {
// Only include Actual and Goal series in the shared tooltip.
const points = this.points.filter(point => {
return point.series.name === 'Actual' || point.series.name === 'Goal';
});
let tooltipHtml = `<b>${this.x}</b><br/>`;
points.forEach(point => {
tooltipHtml += `<span style="color:${point.color}">\u25CF</span> ${point.series.name}: <b>${point.y}</b><br/>`;
});
return tooltipHtml;
},
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
plotOptions: {
spline: {
marker: {
enabled: true
},
showInLegend: true
},
areaspline: {
stacking: 'normal',
showInLegend: false
}
},
series: series
});