ECharts Responsive
ECharts displays charts within a DOM node (container) specified by the user with a given width and height.
Sometimes, we want the charts to be displayed well on both PC and mobile devices, achieving a responsive design. To address this, ECharts has enhanced the positioning settings of components and implemented adaptive capabilities similar to CSS Media Query.
ECharts Component Positioning and Layout
Most 'components' and 'series' follow two positioning methods.
left/right/top/bottom/width/height Positioning Method
Each of these six values can be an 'absolute value', 'percentage', or 'position description'.
-
Absolute Value
The unit is browser pixels (px), written in number
form (without units). For example, {left: 23, height: 400}
.
-
Percentage
Represents a percentage of the DOM container's width and height, written in string
form. For example, {right: '30%', bottom: '40%'}
.
-
Position Description
- Can set
left: 'center'
, indicating horizontal centering. - Can set
top: 'middle'
, indicating vertical centering.
These six values are similar to the six values in CSS:
- left: Distance from the left boundary of the DOM container.
- right: Distance from the right boundary of the DOM container.
- top: Distance from the top boundary of the DOM container.
- bottom: Distance from the bottom boundary of the DOM container.
- width: Width.
- height: Height.
In the horizontal direction, among left, right, and width, only two values need to be specified, as any two values can determine the position and size of the component, such as left and right or right and width. In the vertical direction, top, bottom, and height are similar and need not be repeated.
center / radius Positioning Method
-
center
Is an array representing [x, y]
, where x
and y
can be 'absolute values' or 'percentages', with the same meanings as previously described.
-
radius
Is an array representing [inner radius, outer radius]
, where the inner and outer radii can be 'absolute values' or 'percentages', with the same meanings as previously described.
Percentage settings are very useful when adapting to container size changes.
Horizontal and Vertical
ECharts' 'narrow and long' components (such as legend, visualMap, dataZoom, timeline, etc.) generally provide options for 'horizontal layout' and 'vertical layout'. For example, on narrow mobile screens, 'vertical layout' may be suitable; on PC wide screens, 'horizontal layout' may be suitable.
The settings for horizontal and vertical layouts are usually on the 'component' or 'series' configuration item, set to 'horizontal' or 'vertical'.
Example
In the following example, you can try dragging the circle at the bottom right, and the chart will change with the screen size, with the legend and series automatically adjusting their layout positions and methods.
In this example, we use jQuery to load external data, and we need to include the jQuery library when using it.
Example
$.when(
$.getScript('https://www.tutorialpro.org/static/js/timelineGDP.js'),
$.getScript('https://www.tutorialpro.org/static/js/draggable.js')
).done(function () {
draggable.init(
$('div[_echarts_instance_]')[0],
myChart,
{
width: 700,
height: 400,
throttle: 70
}
);
myChart.hideLoading();
option = {
baseOption: {
title : {
text: 'Nightingale Rose Diagram',
subtext: 'Purely Fictional',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
{
"data": ['rose1', 'rose2', 'rose3', 'rose4', 'rose5', 'rose6', 'rose7', 'rose8'],
"toolbox": {
"show": true,
"feature": {
"mark": { "show": true },
"dataView": { "show": true, "readOnly": false },
"magicType": {
"show": true,
"type": ['pie', 'funnel']
},
"restore": { "show": true },
"saveAsImage": { "show": true }
}
},
"calculable": true,
"series": [
{
"name": "Radius Mode",
"type": "pie",
"roseType": "radius",
"label": {
"normal": {
"show": false
},
"emphasis": {
"show": true
}
},
"lableLine": {
"normal": {
"show": false
},
"emphasis": {
"show": true
}
},
"data": [
{ "value": 10, "name": 'rose1' },
{ "value": 5, "name": 'rose2' },
{ "value": 15, "name": 'rose3' },
{ "value": 25, "name": 'rose4' },
{ "value": 20, "name": 'rose5' },
{ "value": 35, "name": 'rose6' },
{ "value": 30, "name": 'rose7' },
{ "value": 40, "name": 'rose8' }
]
},
{
"name": "Area Mode",
"type": "pie",
"roseType": "area",
"data": [
{ "value": 10, "name": 'rose1' },
{ "value": 5, "name": 'rose2' },
{ "value": 15, "name": 'rose3' },
{ "value": 25, "name": 'rose4' }
]
}
]
}
{value:20, name:'rose5'}, {value:35, name:'rose6'}, {value:30, name:'rose7'}, {value:40, name:'rose8'} ] } ] }, media: [ { option: { legend: { right: 'center', bottom: 0, orient: 'horizontal' }, series: [ { radius: [20, '50%'], center: ['25%', '50%'] }, { radius: [30, '50%'], center: ['75%', '50%'] } ] } }, { query: { minAspectRatio: 1 }, option: { legend: { right: 'center', bottom: 0, orient: 'horizontal' }, series: [ { radius: [20, '50%'], center: ['25%', '50%'] }, { radius: [30, '50%'], center: ['75%', '50%'] } ] } }, { query: { maxAspectRatio: 1 }, option: { legend: { right: 'center', bottom: 0, orient: 'horizontal' }, series: [ { radius: [20, '50%'], center: ['50%', '30%'] },
{
radius: [30, '50%'],
center: ['50%', '70%']
}
]
}
},
{
query: {
maxWidth: 500
},
option: {
legend: {
right: 10,
top: '15%',
orient: 'vertical'
},
series: [
{
radius: [20, '50%'],
center: ['50%', '30%']
},
{
radius: [30, '50%'],
center: ['50%', '75%']
}
]
}
}
]
};
Currently supports three properties: width, height, and aspectRatio (aspect ratio). Each property can be prefixed with min or max. For example, minWidth: 200 means 'width greater than or equal to 200px'. Writing two properties together means 'and', for example: {minWidth: 200, maxHeight: 300} means 'width greater than or equal to 200px and height less than or equal to 300px'.
### Option
Since the option in media is an 'atomic option', theoretically, any configuration item can be written. However, generally, we only write those related to layout positioning, such as taking a part of the query option from the example above:
media: [ ..., { query: { maxAspectRatio: 1 // When the aspect ratio is less than 1. }, option: { legend: { // Legend placed at the bottom center. right: 'center', bottom: 0, orient: 'horizontal' // Legend laid out horizontally. }, series: [ // Two pie charts laid out side by side. { radius: [20, '50%'], center: ['50%', '30%'] }, { radius: [30, '50%'], center: ['50%', '70%'] } ] } }, { query: { maxWidth: 500 // When the container width is less than 500. }, option: { legend: { right: 10, // Legend placed on the right center. top: '15%', orient: 'vertical' // Vertical layout. }, series: [ // Two pie charts laid out vertically. { radius: [20, '50%'], center: ['50%', '30%'] }, { radius: [30, '50%'], center: ['50%', '75%'] } ] } }, ... ]
### Priority When Multiple Queries Are Satisfied
Note that multiple queries can be satisfied simultaneously, and all will be merged with the option, with those defined later having higher priority.
### Default Query
If a query is not written in a media item, it represents the 'default value', meaning this option is adopted when none of the rules are satisfied.
### Considerations for Real-Time Changes in Container Size
In many cases, the container DOM node does not need to change size arbitrarily with dragging, but rather is set to a few typical sizes based on different terminals.
However, if the container DOM node needs to change size arbitrarily with dragging, it is currently necessary to pay attention to this: A configuration item, if it appears in one query option, must also appear in other query options, otherwise it cannot revert to the original state. (left/right/top/bottom/width/height are not subject to this restriction.)
### Media in 'Composite Option' Does Not Support Merge
Below we use jQuery to load external data, and we need to include the jQuery library when using it. This example is combined with a timeline:
## Example
$.when( $.getScript('https://www.tutorialpro.org/static/js/timelineGDP.js'), $.getScript('https://www.tutorialpro.org/static/js/draggable.js') ).done(function () {
draggable.init(
$('div[_echarts_instance_]')[0],
myChart,
{
width: 700,
height: 630,
lockY: true,
throttle: 70
}
);
myChart.hideLoading();
var categoryData = [
'Beijing', 'Tianjin', 'Hebei', 'Shanxi', 'Inner Mongolia', 'Liaoning', 'Jilin', 'Heilongjiang',
'Shanghai', 'Jiangsu', 'Zhejiang', 'Anhui', 'Fujian', 'Jiangxi', 'Shandong', 'Henan',
'Hubei', 'Hunan', 'Guangdong', 'Guangxi', 'Hainan', 'Chongqing', 'Sichuan', 'Guizhou',
'Yunnan', 'Tibet', 'Shaanxi', 'Gansu', 'Qinghai', 'Ningxia', 'Xinjiang'
];
option = {
baseOption: {
timeline: {
axisType: 'category',
autoPlay: true,
playInterval: 1000,
data: [
'2002-01-01', '2003-01-01', '2004-01-01',
'2005-01-01', '2006-01-01', '2007-01-01',
'2008-01-01', '2009-01-01', '2010-01-01',
'2011-01-01'
],
label: {
formatter: function (s) {
return (new Date(s)).getFullYear();
}
}
},
title: {
subtext: 'Media Query Example'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'value',
name: 'GDP (billion yuan)',
max: 30000,
data: null
},
yAxis: {
type: 'category',
data: categoryData,
axisLabel: { interval: 0 },
splitLine: { show: false }
},
legend: {
data: ['Primary Industry', 'Secondary Industry', 'Tertiary Industry', 'GDP', 'Finance', 'Real Estate'],
selected: {
'GDP': false, 'Finance': false, 'Real Estate': false
}
},
calculable: true,
series: [ {name: 'GDP', type: 'bar'}, {name: 'Finance', type: 'bar'}, {name: 'Real Estate', type: 'bar'}, {name: 'Primary Industry', type: 'bar'}, {name: 'Secondary Industry', type: 'bar'}, {name: 'Tertiary Industry', type: 'bar'}, {name: 'GDP Proportion', type: 'pie'} ]}, media: [ { option: { legend: { orient: 'horizontal', left: 'right', itemGap: 10 }, grid: { left: '10%', top: 80, right: 90, bottom: 100 }, xAxis: { nameLocation: 'end', nameGap: 10, splitNumber: 5, splitLine: { show: true } }, timeline: { orient: 'horizontal', inverse: false, left: '20%', right: '20%', bottom: 10, height: 40 }, series: [ {name: 'GDP Proportion', center: ['75%', '30%'], radius: '28%'} ] } }, { query: {maxWidth: 670, minWidth: 550}, option: { legend: { orient: 'horizontal', left: 200, itemGap: 5 }, grid: { left: '10%', top: 80, right: 90, bottom: 100 }, xAxis: { nameLocation: 'end', nameGap: 10, splitNumber: 5, splitLine: { show: true }, timeline: { orient: 'horizontal', inverse: false, left: '20%', right: '20%', bottom: 10, height: 40 }, series: [ {name: 'GDP Proportion', center: ['75%', '30%'], radius: '28%'} ] }, { query: {maxWidth: 550}, option: { legend: { orient: 'vertical', left: 'right', itemGap: 5 }, grid: { left: 55, top: '32%', right: 100, bottom: 50 }, xAxis: { nameLocation: 'middle', nameGap: 25, splitNumber: 3 }, timeline: { orient: 'vertical', inverse: true, right: 10, top: 150, bottom: 10, width: 55 }, series: [ {name: 'GDP Proportion', center: ['45%', '20%'], radius: '28%'} ] } } ], options: [ { title: {text: '2002 National Macro Economic Indicators'}, series: [ {data: dataMap.dataGDP['2002']}, {data: dataMap.dataFinancial['2002']}, {data: dataMap.dataEstate['2002']}, {data: dataMap.dataPI['2002']},
{data: dataMap.dataSI['2002']},
{data: dataMap.dataTI['2002']},
{data: [
{name: 'Primary Industry', value: dataMap.dataPI['2002sum']},
{name: 'Secondary Industry', value: dataMap.dataSI['2002sum']},
{name: 'Tertiary Industry', value: dataMap.dataTI['2002sum']}
]}
]
},
{
title : {text: '2003 National Macro Economic Indicators'},
series : [
{data: dataMap.dataGDP['2003']},
{data: dataMap.dataFinancial['2003']},
{data: dataMap.dataEstate['2003']},
{data: dataMap.dataPI['2003']},
{data: dataMap.dataSI['2003']},
{data: dataMap.dataTI['2003']},
{data: [
{name: 'Primary Industry', value: dataMap.dataPI['2003sum']},
{name: 'Secondary Industry', value: dataMap.dataSI['2003sum']},
{name: 'Tertiary Industry', value: dataMap.dataTI['2003sum']}
]}
]}
},
{
title : {text: '2004 National Macro Economic Indicators'},
series : [
{data: dataMap.dataGDP['2004']},
{data: dataMap.dataFinancial['2004']},
{data: dataMap.dataEstate['2004']},
{data: dataMap.dataPI['2004']},
{data: dataMap.dataSI['2004']},
{data: dataMap.dataTI['2004']},
{data: [
{name: 'Primary Industry', value: dataMap.dataPI['2004sum']},
{name: 'Secondary Industry', value: dataMap.dataSI['2004sum']},
{name: 'Tertiary Industry', value: dataMap.dataTI['2004sum']}
]}
]}
},
{
title : {text: '2005 National Macro Economic Indicators'},
series : [
{data: dataMap.dataGDP['2005']},
{data: dataMap.dataFinancial['2005']}, {data: dataMap.dataEstate['2005']}, {data: dataMap.dataPI['2005']}, {data: dataMap.dataSI['2005']}, {data: dataMap.dataTI['2005']}, {data: [ {name: 'Primary Industry', value: dataMap.dataPI['2005sum']}, {name: 'Secondary Industry', value: dataMap.dataSI['2005sum']}, {name: 'Tertiary Industry', value: dataMap.dataTI['2005sum']} ]} ] }, { title: {text: '2006 National Macroeconomic Indicators'}, series: [ {data: dataMap.dataGDP['2006']}, {data: dataMap.dataFinancial['2006']}, {data: dataMap.dataEstate['2006']}, {data: dataMap.dataPI['2006']}, {data: dataMap.dataSI['2006']}, {data: dataMap.dataTI['2006']}, {data: [ {name: 'Primary Industry', value: dataMap.dataPI['2006sum']}, {name: 'Secondary Industry', value: dataMap.dataSI['2006sum']}, {name: 'Tertiary Industry', value: dataMap.dataTI['2006sum']} ]} ] }, { title: {text: '2007 National Macroeconomic Indicators'}, series: [ {data: dataMap.dataGDP['2007']}, {data: dataMap.dataFinancial['2007']}, {data: dataMap.dataEstate['2007']}, {data: dataMap.dataPI['2007']}, {data: dataMap.dataSI['2007']}, {data: dataMap.dataTI['2007']}, {data: [ {name: 'Primary Industry', value: dataMap.dataPI['2007sum']}, {name: 'Secondary Industry', value: dataMap.dataSI['2007sum']}, {name: 'Tertiary Industry', value: dataMap.dataTI['2007sum']} ]} ] }, {
{
"title": { "text": "2008 National Macro Economic Indicators" },
"series": [
{ "data": dataMap.dataGDP['2008'] },
{ "data": dataMap.dataFinancial['2008'] },
{ "data": dataMap.dataEstate['2008'] },
{ "data": dataMap.dataPI['2008'] },
{ "data": dataMap.dataSI['2008'] },
{ "data": dataMap.dataTI['2008'] },
{ "data": [
{ "name": "Primary Industry", "value": dataMap.dataPI['2008sum'] },
{ "name": "Secondary Industry", "value": dataMap.dataSI['2008sum'] },
{ "name": "Tertiary Industry", "value": dataMap.dataTI['2008sum'] }
]}
]
},
{
"title": { "text": "2009 National Macro Economic Indicators" },
"series": [
{ "data": dataMap.dataGDP['2009'] },
{ "data": dataMap.dataFinancial['2009'] },
{ "data": dataMap.dataEstate['2009'] },
{ "data": dataMap.dataPI['2009'] },
{ "data": dataMap.dataSI['2009'] },
{ "data": dataMap.dataTI['2009'] },
{ "data": [
{ "name": "Primary Industry", "value": dataMap.dataPI['2009sum'] },
{ "name": "Secondary Industry", "value": dataMap.dataSI['2009sum'] },
{ "name": "Tertiary Industry", "value": dataMap.dataTI['2009sum'] }
]}
]
},
{
"title": { "text": "2010 National Macro Economic Indicators" },
"series": [
{ "data": dataMap.dataGDP['2010'] },
{ "data": dataMap.dataFinancial['2010'] },
{ "data": dataMap.dataEstate['2010'] },
{ "data": dataMap.dataPI['2010'] },
{ "data": dataMap.dataSI['2010'] },
{ "data": dataMap.dataTI['2010'] },
{ "data": [
{ "name": "Primary Industry", "value": dataMap.dataPI['2010sum'] },
{ "name": "Secondary Industry", "value": dataMap.dataSI['2010sum'] }
]}
]
}
{name: 'Tertiary Industry', value: dataMap.dataTI['2010sum']}
]
]
},
{
title: {text: '2011 National Macro Economic Indicators'},
series: [
{data: dataMap.dataGDP['2011']},
{data: dataMap.dataFinancial['2011']},
{data: dataMap.dataEstate['2011']},
{data: dataMap.dataPI['2011']},
{data: dataMap.dataSI['2011']},
{data: dataMap.dataTI['2011']},
{data: [
{name: 'Primary Industry', value: dataMap.dataPI['2011sum']},
{name: 'Secondary Industry', value: dataMap.dataSI['2011sum']},
{name: 'Tertiary Industry', value: dataMap.dataTI['2011sum']}
]}
]
}
]
};
myChart.setOption(option);
});