Apache ECharts - scale graphic on window resize - echarts

I'm able to add a graphic to an EChart and center it in the canvas. But I can only make it a fixed width - I want it to scale when the chart resizes. Can see an example here:
https://codepen.io/bennyb/pen/qBKPWNM
option = {
tooltip: {
trigger: "item"
},
legend: {
bottom: 20,
left: "center"
},
graphic: [
{
id: 'img',
type: "image",
top: 'center',
left: 'center',
style: {
image: "http://cdn.onlinewebfonts.com/svg/img_155117.png",
width: 200,
height: 200
}
}
],
series: [
{
name: "Let vs Available",
type: "pie",
color: [
"#00ABAB",
"#007680"
],
radius: [
"45%",
"70%"
],
avoidLabelOverlap: false,
label: {
show: false,
position: "center"
},
emphasis: {
label: {
show: true,
fontSize: "15",
fontWeight: "bold"
}
},
labelLine: {
show: true
},
data: [
{
value: 31,
name: "Let"
},
{
value: 69,
name: "Available"
}
]
}
]
}
I'm able to add an id to the graphic, is there a way I can target that to resize the image on update?

Related

In Echarts, how to title/label series (pies) in nested pie chart

In Apache Echarts, when using multiple pie charts (e.g. nested pies, or even side-by-side pies), how do we add a title to each pie to signify what the pie represents? While the "title" option can accept an array of titles, there isn't a good way to position them so that they are above, within or in some other way related to the respective pies they are meant to label. It's as if there's a missing concept of a seriesLabel / seriesTitle that sits conceptually between the chart title and the individual item labels.
Series item labels are already in use for the items (pie slices) so cannot be used with position: center, and that wouldn't help with nested pies anyway since there's only room for one label at the center.
Here are my nested pies. I used an image editor to add labels where I might want them - hugging the pies they each label. That's what I'm trying to accomplish.
I do not understand what is your problem with the array of titles...
Here is a simple example showing how to give a title to each pie:
const data = [
{
name: 'Foo',
value: 10
},
{
name: 'Bar',
value: 20
},
{
name: 'Baz',
value: 15
}
];
let option = {
title: [
{
text: 'Pie 1',
subtext: 'Left',
left: '46px',
textAlign: 'center'
},
{
text: 'Pie 2',
subtext: 'Center',
left: '146px',
textAlign: 'center'
},
{
text: 'Pie 3',
subtext: 'Right',
left: '246px',
textAlign: 'center'
}
],
series: [
{
type: 'pie',
radius: '42px',
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
left: 0,
right: '66%',
top: 0,
bottom: 0
},
{
type: 'pie',
radius: '42px',
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
left: '33%',
right: '33%',
top: 0,
bottom: 0
},
{
type: 'pie',
radius: '42px',
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
left: '66%',
right: 0,
top: 0,
bottom: 0
}
]
};
let myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
#main {
width: 300px;
height: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/echarts#5.4.1/dist/echarts.min.js"></script>
<div id="main"></div>
EDIT 1
Same example with nested pies:
const data = [
{
name: 'Foo',
value: 10
},
{
name: 'Bar',
value: 20
},
{
name: 'Baz',
value: 15
}
];
let option = {
title: [
{
text: 'Pie 1',
left: '48%',
textAlign: 'center'
},
{
text: 'Pie 2',
left: '48%',
top: '26%',
textAlign: 'center'
}
],
series: [
{
type: 'pie',
radius: ['120px', '90px'],
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
top: '10px'
},
{
type: 'pie',
radius: '42px',
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
top: '10px'
}
]
};
let myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
#main {
width: 300px;
height: 300px;
}
<script src="https://cdn.jsdelivr.net/npm/echarts#5.4.1/dist/echarts.min.js"></script>
<div id="main"></div>
EDIT 2
If you want something completely responsive with nested pies, indeed, I do not know the recipe using a simple array of titles...
But you can do this somehow creating two containers, which means each pie will be in its own <canvas> element. Then you can use CSS to give your inner pie an absolute position.
There is extra work to handle the behavior of both charts on resize. Your <canvas> elements should always be squares. In other words, their width and height should stay equal.
When you resize the window, you have to get its width and height to determine if you have a horizontal display or a vertical one. In both cases, take the smallest value and resize outer and inner containers (width and height) with it. You can even get a variable font size thanks to this value.
Of course, you should avoid px in your options. Prefer % instead.
Here is the code:
const data = [
{
name: 'Foo',
value: 10
},
{
name: 'Bar',
value: 20
},
{
name: 'Baz',
value: 15
}
];
let outerOption = {
title: {
text: 'Pie 1',
top: '2%',
left: '50%',
textAlign: 'center'
},
series: [
{
type: 'pie',
radius: ['100%', '80%'],
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
top: '10%'
}
]
};
let innerOption = {
title: {
text: 'Pie 2',
top: '25%',
left: '50%',
textAlign: 'center'
},
series: [
{
type: 'pie',
radius: '50%',
center: ['50%', '50%'],
data,
label: {
position: 'inner'
},
top: '10%'
}
]
};
let outerChart = echarts.init(document.getElementById('outer')),
innerChart = echarts.init(document.getElementById('inner'));
outerChart.setOption(outerOption);
innerChart.setOption(innerOption);
function resize(container, size) {
container.resize({
width: size,
height: size
});
container.setOption({
title: {
textStyle: {
fontSize: Math.round(size / 20)
}
}
});
}
['load', 'resize'].forEach(event => {
window.addEventListener(event, () => {
let width = window.innerWidth,
height = window.innerHeight,
size = width;
if (width > height) {
size = height;
}
resize(outerChart, size);
resize(innerChart, size);
});
});
body {
margin: 0;
}
#outer, #inner {
width: 100vh;
height: 100vh;
}
#inner {
position: absolute;
top: 0;
left: 0;
}
<script src="https://cdn.jsdelivr.net/npm/echarts#5.4.1/dist/echarts.min.js"></script>
<div id="outer"></div>
<div id="inner"></div>

How to set a second variable for Apcahe eCharts detail.formatter?

My data lives inside a variable named gaugeData. And it has two properties value and date.
And in Apache eCharts I am trying to use detail.formatter to create two headings with different text styles, like this:
formatter: ['{header|{value}}', '{subHeader|{date}}'].join('\n')
The first header displays the value, and the second subHeader displays the date.
Currently, the value is displaying correctly but the date is not.
Here is a screenshot of how it looks:
How do I make the date also work as a variable?
I don't care if date lives outside the gaugeData, I just need it to be a variable of some kind.
Here is my full code:
const gaugeData = [
{
value: 80,
date: '15-30-2022',
},
];
const gaugeOption = {
series: [
{
data: gaugeData,
type: 'gauge',
startAngle: 180,
endAngle: 0,
min: 0,
max: 100,
splitNumber: 3,
pointer: {
icon: 'circle',
length: '12%',
width: 50,
offsetCenter: [0, '-90%'],
itemStyle: {
color: '#FFFFFF',
borderColor: borderColor,
borderWidth: 5,
shadowColor: 'rgba(10, 31, 68, 0.5)',
shadowBlur: 1,
shadowOffsetY: 1,
},
},
axisLine: {
show: true,
roundCap: true,
lineStyle: {
width: 9,
color: [
[0.5, '#e76262'],
[0.54],
[0.66, '#f9cf4a'],
[0.7],
[0.83, '#eca336'],
[0.87],
[1, '#3ece80'],
],
},
},
axisTick: {
length: 2,
lineStyle: {
color: '#8a94a6',
width: 2,
},
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
title: {
show: false,
},
detail: {
rich: {
header: {
fontSize: 36,
fontWeight: 700,
fontFamily: 'Open Sans',
color: '#0a1f44',
},
subHeader: {
fontSize: 16,
fontWeight: 400,
fontFamily: 'Open Sans',
color: '#8a94a6',
},
},
formatter: ['{header|{value}}', '{subHeader|{date}}'].join('\n'),
offsetCenter: [0, '-20%'],
valueAnimation: true,
},
},
],
};
Figured it out.
The formatter can take a callback function where you can reference any other variable you like.
So when using Vue my data variables can look like this:
const scoreDate = ref('15-30-2022');
const scoreValue = ref(80);
const gaugeData = [
{
value: scoreValue.value,
},
];
And the formatter property of the options object looks like this:
formatter: function (data: number) {
return `{header|${data}} \n {subHeader|${scoreDate.value}}`;
},

How to change label color for line charts.js?

I try to chanage a color of line lables:
exmaple of label pic
The line has settings:
const linedataset = {
type: 'line',
label: 'label',
data: xavarage,
order: 1,
borderColor: 'rgb(225, 54, 54)',
backgroundColor: lineBackground,
};
And common settings are:
const chartoptions = {
hoverBackgroundColor,
backgroundColor,
responsive: true,
scales: {
x: {},
y: {
min: 0,
},
},
plugins: {
title: {
display: true,
text: this.selectedCategory?.full,
font: {
size: 20,
},
},
datalabels: {
anchor: 'end',
align: 'end',
},
},
};
I have tried to usse the following code:
options: {
legend: {
color: "#ccc"
}
}
But it does not work too. How to set color of label text (line graphic)?
Your chart uses chartjs-plugin-datalabels. Therefore, you need to define color inside datalabels as follows:
datalabels: {
color: '#ccc',
anchor: 'end',
align: 'end'
},

How to display an SVG as `data.name` in gauge chart in ECharts?

I want to display the following image instead of Label in a gauge chart:
<?xml version="1.0" encoding="UTF-8"?>
<svg width="33.614mm" height="23.031mm" version="1.1" viewBox="0 0 33.614 23.031" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(-34.286 -116.77)">
<path
d="m35.218 128.28 2.6458-10.583 2.6458 10.583 2.6458 10.583 5.2916-21.166 5.2916 21.166 5.2916-21.166 5.2916 21.166 2.6458-10.583v0"
fill="none" stroke="#000" stroke-linecap="round"
stroke-linejoin="round" stroke-width="1.865"
/>
</g>
</svg>
Here is the chart:
option = {
series: [
{
type: 'gauge',
startAngle: 200,
endAngle: -20,
center: ['50%', '70%'],
axisLine: {
lineStyle: {
width: 8,
color: [
[0.3, 'red'],
[0.7, 'orange'],
[1, '#96BE0F']
]
}
},
pointer: {
itemStyle: {
color: 'auto'
}
},
axisTick: {
distance: -15,
length: 5,
lineStyle: {
color: '#fff',
width: 1
}
},
splitLine: {
distance: -15,
length: 8,
lineStyle: {
color: '#fff',
width: 2
}
},
axisLabel: {
color: 'auto',
distance: -20,
fontSize: 12
},
detail: {
valueAnimation: true,
formatter: '{value} %',
color: 'auto',
},
data: [
{
value: 50,
name: 'Label',
// image: 'path://m57.046 134.9v-13.229m3.9688 12.7h2.6458v-12.171h-2.6458m-22.49 12.7h18.521v2.6458l3.9687 1e-5 1e-6 -18.521h-3.9688v2.6458h-18.521v0h-1e-6'
}
],
title: {
fontSize: 20,
fontWeight: 800,
fontFamily: 'Arial',
color: 'grey',
offsetCenter: [0, '-70%'],
// image: 'path://m57.046 134.9v-13.229m3.9688 12.7h2.6458v-12.171h-2.6458m-22.49 12.7h18.521v2.6458l3.9687 1e-5 1e-6 -18.521h-3.9688v2.6458h-18.521v0h-1e-6'
},
}
]
};
I want to insert that image with fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.865".
I only could output the image in a pictorial chart, but even then I could not make it not to fill anything.
Update
I was able to output a PNG image using graphic, but not an SVG. Has anyone have a clue why? How can I output an SVG image?
option = {
xAxis: {show: false},
yAxis: {show: false},
series: [
{
type: 'gauge',
startAngle: 200,
endAngle: -20,
center: ['50%', '70%'],
axisLine: {
lineStyle: {
width: 8,
color: [
[0.3, 'red'],
[0.7, 'orange'],
[1, '#96BE0F']
]
}
},
pointer: {
itemStyle: {
color: 'auto'
}
},
axisTick: {
distance: -15,
length: 5,
lineStyle: {
color: '#fff',
width: 1
}
},
splitLine: {
distance: -15,
length: 8,
lineStyle: {
color: '#fff',
width: 2
}
},
axisLabel: {
color: 'auto',
distance: -20,
fontSize: 12
},
detail: {
valueAnimation: true,
formatter: '{value} %',
color: 'auto'
},
data: [50]
},
],
graphic: {
type: 'image',
left: 'center',
bottom: 495,
offsetCenter: [0, '-60%'],
style: {
image: 'https://i.imgur.com/4KIo3sb.png',
// image: 'path://M29.902,23.275c1.86,0,3.368-1.506,3.368-3.365c0-1.859-1.508-3.365-3.368-3.365 c-1.857,0-3.365,1.506-3.365,3.365C26.537,21.769,28.045,23.275,29.902,23.275z M36.867,30.74c-1.666-0.467-3.799-1.6-4.732-4.199 c-0.932-2.6-3.131-2.998-4.797-2.998s-7.098,3.894-7.098,3.894c-1.133,1.001-2.1,6.502-0.967,6.769 c1.133,0.269,1.266-1.533,1.934-3.599c0.666-2.065,3.797-3.466,3.797-3.466s0.201,2.467-0.398,3.866 c-0.599,1.399-1.133,2.866-1.467,6.198s-1.6,3.665-3.799,6.266c-2.199,2.598-0.6,3.797,0.398,3.664 c1.002-0.133,5.865-5.598,6.398-6.998c0.533-1.397,0.668-3.732,0.668-3.732s0,0,2.199,1.867c2.199,1.865,2.332,4.6,2.998,7.73 s2.332,0.934,2.332-0.467c0-1.401,0.269-5.465-1-7.064c-1.265-1.6-3.73-3.465-3.73-5.265s1.199-3.732,1.199-3.732 c0.332,1.667,3.335,3.065,5.599,3.399C38.668,33.206,38.533,31.207,36.867,30.74z',
width: 80
}
}
}

How to use gradient and single color at the same time in Apex Chart?

How to add gradient (mixed with two colors) for one bar chart column and on top of that stack another column with (single color)?
Currently, I am trying to figure it out how to implement gradient and single color pattern in ApexChart.js. As for now, I can only use one at the same time...
JavaScript:
var colors = ["#A865AA", "#222130",];
var dataColors = $("#monthlycost-ApexChart").data('colors');
if (dataColors) {
colors = dataColors.split(",");
}
var options = {
chart: {
height: 260,
type: 'bar',
stacked: true,
stackType: '10%',
toolbar: {
show: false
},
},
stroke: {
curve: 'smooth',
width: 1
},
grid: {
column: {
colors: ['transparent', '#e5e5e5'],
},
},
plotOptions: {
bar: {
columnWidth: '20%',
endingShape: 'rounded',
}
},
dataLabels: {
enabled: false
},
series: [{
name: 'Cost',
data: [5.7, 5.7, 5.4, 5.4, 5.2, 7.8, 5.6, 5.4, 5.7, 0, 0, 0]
}, {
data: [12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12]
}],
xaxis: {
labels: {
show: true,
style: {
fontSize: '10px'
},
padding: {
top: 0,
bottom: 20
},
},
offsetY: -10,
position: 'bottom',
axisBorder: {
show: false
},
axisTicks: {
show: false
},
lines: {
show: false
},
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
padding: {
top: -5,
bottom: 0
},
},
yaxis: {
axisBorder: {
show: false
},
axisTicks: {
show: false
},
lines: {
show: false
},
title: {
text: '£0,000',
style: {
fontWeight: 400,
fontSize: '9px',
}
},
tickAmount: 5,
forceNiceScale: false,
decimalsInFloat: 0,
max: 10,
},
fill: {
type: "gradient",
/* gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
type: 'vertical',
opacityTo: 0.9,
colorStops: [
{
offset: 40,
color: "#EF9432",
opacity: 1
},
{
offset: 100,
color: "#A865AA",
opacity: 1
}
]
}*/
},
legend: {
show: false,
},
colors: colors,
grid: {
row: {
show: false,
},
borderColor: '',
padding: {
bottom: 5,
top: 1
}
}
}
Need to get this
Currently have
You should use distributed property
plotOptions: {
bar: {
distributed: true
}
}