I came across an almost complete solution for my needs in https://github.com/apache/echarts/issues/8034, however, the fill colour isn't being applied correctly, as seen in:
and
Compared to what the issue shows should be something akin to:
I'm not entirely sure if the attached image actually corresponds to the code in the issue though... but the fill apparently should match the line colour, but I'm not seeing this in my testing. I did have to change dimension
in visualMap
from 0 to 1 to get the line segments to change colour. Setting to 0, I get a blue fill + blue line, setting to 2, I get a yellow fill + yellow line, setting to 1, I get a blue fill + changing line colours...
Current echarts setup (data is x-axis: 1-N (simple index value), y-axis: values 0 <=> 1000):
async function createLineChartNew(element) {
echarts.registerTheme("sauce", theme.getTheme("dynamic"));
addEventListener("resize", resizeCharts);
const dataPoints = defaultLineChartLen;
const fields = [
{
id: "power",
name: "Power",
color: "rgb(255,255,255)",
domain: [0, 1000],
rangeAlpha: [0.4, 1],
points: [],
get: (x) => x.state.power || 0,
fmt: (x) => H.power(x, { seperator: " ", suffix: true }),
},
];
var options = {
title: {
show: false,
},
tooltip: {
className: "ec-tooltip",
trigger: "axis",
axisPointer: {
type: "cross",
lineStyle: {
type: "dashed",
},
label: {
backgroundColor: "#38b5ca",
},
},
},
toolbox: {
show: false,
},
xAxis: {
boundaryGap: false,
splitLine: {
lineStyle: {
color: "#ededed",
},
},
axisLine: {
lineStyle: {
color: "#ededed",
},
},
axisPointer: {
snap: true,
},
axisLabel: {
color: "#e0e0e0",
},
data: Array.from(new Array(dataPoints)).map((x, i) => i),
},
yAxis: {
position: "right",
type: "value",
axisLabel: {
formatter: "{value} BTC",
color: "#e0e0e0",
},
splitLine: {
lineStyle: {
color: "#ededed",
},
},
axisLine: {
lineStyle: {
color: "#ededed",
},
},
min: 0,
max: 800,
},
series: [
{
id: "power",
name: "Some title",
type: "line",
smooth: true,
showSymbol: false,
symbolSize: 6,
symbol: "circle",
lineStyle: {
// color: colors.GREEN, // NEED TO MAP THIS VALUE FOR EVERY SECTION
// shadowColor: colors.GREEN, // NEED TO MAP THIS VALUE FOR EVERY SECTION
shadowBlur: 4,
},
itemStyle: {
color: "#38b5ca",
},
areaStyle: {
normal: {
// NEED TO MAP THIS VALUE FOR EVERY SECTION
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
// offset: 0,
// color: 'rgb(255, 255, 255)'
// }, {
// offset: 1,
// color: colors.GREEN
// }]),
opacity: 0.2,
},
},
},
],
//color: fields.map((f) => f.color),
grid: { top: 0, left: 0, right: 0, bottom: 0 },
legend: { show: false },
visualMap: {
type: "piecewise",
show: false,
dimension: 1,
pieces: [
{
lte: 251,
color: "rgb(11, 190, 235)",
},
{
gt: 251,
lte: 302,
color: "rgb(255, 197, 0)",
},
{
gt: 302,
lte: 492,
color: "rgb(251, 139, 4)",
},
{
gt: 492,
color: "rgb(237, 31, 143)",
},
],
},
};
const lineChart = echarts.init(element, "sauce", { renderer: "svg" });
lineChart.setOption(options);
chartRefs.add(new WeakRef(lineChart));
return lineChart;
}
function bindLineChartNew(lineChart, renderer)
{
const dataPoints = defaultLineChartLen;
let lastRender = 0;
const fields = [
{
id: "power",
name: "Power",
color: "rgb(255,255,255)",
domain: [0, 1000],
rangeAlpha: [0.4, 1],
points: [],
get: (x) => x.state.power || 0,
fmt: (x) => H.power(x, { seperator: " ", suffix: true }),
},
];
renderer.addCallback((data) => {
const now = Date.now();
if (now - lastRender < 900)
return;
lastRender = now;
if (data && data.state) {
for (const x of fields) {
x.points.push(x.get(data));
while (x.points.length > dataPoints) {
x.points.shift();
}
}
}
lineChart.setOption({
xAxis: [
{
data: Array.from(sauce.data.range(dataPoints)),
},
],
series: fields.map((field) => ({
data: field.points,
name: typeof field.name === "function" ? field.name() : field.name,
})),
});
});
}
EDIT: updated code after trying to adapt answer (whole area changes instead of particular sections):
var seriesList = [];
var filteredDatasets = [];
var points = [];
async function createLineChartNew(element) {
echarts.registerTheme("sauce", theme.getTheme("dynamic"));
addEventListener("resize", resizeCharts);
const dataPoints = defaultLineChartLen;
var options = {
dataset: filteredDatasets,
title: {
show: false,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: Array.from(new Array(dataPoints)).map((x, i) => i),
},
yAxis: {
type: "value",
axisLabel: {
formatter: "{value} W",
},
},
series: seriesList,
grid: { top: 0, left: 0, right: 0, bottom: 0 },
};
const lineChart = echarts.init(element, "sauce", { renderer: "svg" });
lineChart.setOption(options);
chartRefs.add(new WeakRef(lineChart));
return lineChart;
}
var colors = {
ftp: 'rgb(11, 190, 235)',
map: 'rgb(255, 197, 0)',
ac: 'rgb(251, 139, 4)',
nm: 'rgb(237, 31, 143)'
};
function bindLineChartNew(lineChart, renderer)
{
const dataPoints = defaultLineChartLen;
let lastRender = 0;
renderer.addCallback((data) => {
// don't render too often
const now = Date.now();
if (now - lastRender < 900) return;
lastRender = now;
// skip if there is no data
if (!data || !data.state) return;
let power = data.state.power || 0;
// add a new data point, then drop front until desired length
var x = 0;
if (points.length > 0) {
x = points.at(-1).x + 1;
}
points.push({x: x, y: power});
while (points.length > dataPoints) points.shift();
while (filteredDatasets.length > 0) filteredDatasets.shift();
for (let ix = 0; ix < points.length - 1; ++ix)
{
const datasetId = ix;
const datasetSliced = points.slice(ix, ix + 2);
filteredDatasets.push({
id: datasetId,
source: datasetSliced,
});
if (power <= 240)
{
seriesList.push({
type: 'line',
datasetId: datasetId,
color: 'green',
areaStyle: {color: 'lightgreen'}
});
}
else if (power <= 302)
{
seriesList.push({
type: 'line',
datasetId: datasetId,
color: 'red',
areaStyle: {color: 'rgb(255,173,177)'}
});
}
else if (power <= 492)
{
seriesList.push({
type: 'line',
datasetId: datasetId,
color: 'green',
areaStyle: {color: 'lightgreen'}
});
}
else
{
seriesList.push({
type: 'line',
datasetId: datasetId,
color: 'red',
areaStyle: {color: 'rgb(255,173,177)'}
});
}
}
while (seriesList.length > dataPoints) seriesList.shift();
// now update the line chart
lineChart.setOption({
dataset: filteredDatasets,
xAxis: [
{
data: Array.from(sauce.data.range(dataPoints)),
},
],
series: seriesList,
});
});
}
Unfortunately it seems like in visual map there is no access to the line property areaStyle
. Thats why I currently dont see a "clean" solution.
What you could do is precompute parts of your line that should be colored differently and build partial lines for each interval which can be styled individually. I modified this official example to show how it can be done here.
Code:
import * as echarts from 'echarts';
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
const data = [
{x: 0, y: 300}, {x: 1, y: 280}, {x: 2, y: 250}, {x: 3, y: 260}, {x: 4, y: 270}, {x: 5, y: 300}, {x: 6, y: 550}, {x: 7, y: 500},
{x: 8, y: 400}, {x: 9, y: 390}, {x: 10, y: 380}, {x: 11, y: 390}, {x: 12, y: 400}, {x: 13, y: 500}, {x: 14, y: 600}, {x: 15, y: 750},
{x: 16, y: 800}, {x: 17, y: 700}, {x: 18, y: 600}, {x: 19, y: 400}
];
const seriesList = [];
const filteredDatasets = [];
function createSeriesList(data) {
for (let index = 0; index < data.length - 1; index++) {
const datasetId = 'dataset_' + index;
const datasetSliced = data.slice(index, index + 2);
filteredDatasets.push({
id: datasetId,
source: datasetSliced
});
if (index < 6 || index > 16 || (index > 7 && index < 14)) {
seriesList.push({
type: 'line',
datasetId: datasetId,
color: 'green',
areaStyle: { color: 'lightgreen' }
});
} else {
seriesList.push({
type: 'line',
datasetId: datasetId,
color: 'red',
areaStyle: { color: 'rgba(255, 173, 177)' }
});
}
}
}
createSeriesList(data);
option = {
dataset: filteredDatasets,
title: {
text: 'Distribution of Electricity',
subtext: 'Fake Data'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
toolbox: {
show: true,
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
// prettier-ignore
data: ['00:00', '01:15', '02:30', '03:45', '05:00', '06:15', '07:30', '08:45', '10:00', '11:15', '12:30', '13:45', '15:00', '16:15', '17:30', '18:45', '20:00', '21:15', '22:30', '23:45']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} W'
},
axisPointer: {
snap: true
}
},
series: seriesList
};
option && myChart.setOption(option);
Edit
Here is an example with dynamic data. I hope it helps.
Code:
import * as echarts from 'echarts';
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
const dataPoints = 50;
const seriesList = [];
const filteredDatasets = [];
option = {
title: {
show: false
},
dataset: filteredDatasets,
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} W'
}
},
series: seriesList
};
let index = 1;
let lastPoint = { x: 0, power: 300 };
setInterval(function () {
const power = lastPoint.power + (Math.random() * 60 - 30); // random value in [-30, 30]
const point = { x: index, power: power };
if (filteredDatasets.length > dataPoints) {
filteredDatasets.shift();
seriesList.shift();
}
filteredDatasets.push({
id: index,
source: [lastPoint, point]
});
if (power <= 240) {
seriesList.push({
type: 'line',
datasetId: index,
color: 'green',
areaStyle: { color: 'lightgreen' }
});
} else if (power <= 302) {
seriesList.push({
type: 'line',
datasetId: index,
color: 'red',
areaStyle: { color: 'rgb(255,173,177)' }
});
} else if (power <= 492) {
seriesList.push({
type: 'line',
datasetId: index,
color: 'green',
areaStyle: { color: 'lightgreen' }
});
} else {
seriesList.push({
type: 'line',
datasetId: index,
color: 'red',
areaStyle: { color: 'rgb(255,173,177)' }
});
}
// now update the line chart
myChart.setOption({
dataset: filteredDatasets,
series: seriesList
});
index++;
lastPoint = point;
}, 500);
option && myChart.setOption(option);