Apache ECharts is an open-sourced JavaScript visualization tool which runs fluently on PC and mobile devices. Based on Apache ECharts.
Apache ECharts is configured by sending a JSON payload from the server. The itemSelect AJAX event tells which series and data point was clicked: click a point of the chart.
The chart is configured inline with the value facet.
Apache ECharts supports custom themes such as the vintage theme in this example, see Apache ECharts Themes. A chart with its own theme does not follow the color scheme of the page.
<!-- CDATA: the script contains && -->
<script>
//<![CDATA[
// Charts without their own theme follow the color scheme of the page (data-dark on html, set by the theme
// configurator): the widget renders with PrimeFaces.env.getThemeContrast() and is refreshed when it changes.
var echartSchemes = new WeakMap();
function echartFollowScheme() {
var scheme = PrimeFaces.env.getThemeContrast();
Object.values(PrimeFaces.widgets).forEach(function (widget) {
if (widget instanceof PrimeFaces.widget.ExtEChart && !widget.cfg.theme) {
if (echartSchemes.has(widget) && echartSchemes.get(widget) !== scheme && widget.chart) {
widget.refresh(widget.cfg);
}
echartSchemes.set(widget, scheme);
}
});
}
$(window).on('load', echartFollowScheme);
$(document).on('pfAjaxComplete', echartFollowScheme);
new MutationObserver(echartFollowScheme).observe(document.documentElement, {attributes: true, attributeFilter: ['data-dark', 'style']});
//]]>
</script>
<div class="card">
<h5>Basic Usage</h5>
<p>Apache ECharts is configured by sending a JSON payload from the server. The <i>itemSelect</i> AJAX event tells which series and data point was clicked: click a point of the chart.</p>
<h:form id="formBasicUsage">
<p:messages id="messages" showSummary="true" showDetail="true"/>
<pe:echart style="width: 100%; height: 400px;" value="#{eChartController.json}" widgetVar="jsonEChart">
<p:ajax event="itemSelect" listener="#{eChartController.itemSelect}" update="messages"/>
</pe:echart>
</h:form>
</div>
<div class="card">
<h5>Facet Usage</h5>
<p>The chart is configured inline with the <code>value</code> facet.</p>
<h:form id="formFacetUsage">
<p:messages id="messages" showSummary="true" showDetail="true"/>
<pe:echart style="width: 100%; height: 400px;" widgetVar="facetEChart">
<p:ajax event="itemSelect" listener="#{eChartController.itemSelect}" update="messages"/>
<f:facet name="value">
{
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
center: ['50%', '75%'],
radius: '90%',
min: 0,
max: 1,
splitNumber: 8,
axisLine: {
lineStyle: {
width: 6,
color: [
[0.25, '#FF6E76'],
[0.5, '#FDDD60'],
[0.75, '#58D9F9'],
[1, '#7CFFB2']
]
}
},
pointer: {
icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
length: '12%',
width: 20,
offsetCenter: [0, '-60%'],
itemStyle: {
color: 'auto'
}
},
axisTick: {
length: 12,
lineStyle: {
color: 'auto',
width: 2
}
},
splitLine: {
length: 20,
lineStyle: {
color: 'auto',
width: 5
}
},
axisLabel: {
fontSize: 20,
distance: -60,
rotate: 'tangential',
formatter: function (value) {
if (value === 0.875) {
return 'Grade A';
} else if (value === 0.625) {
return 'Grade B';
} else if (value === 0.375) {
return 'Grade C';
} else if (value === 0.125) {
return 'Grade D';
}
return '';
}
},
title: {
offsetCenter: [0, '-10%'],
fontSize: 20
},
detail: {
fontSize: 30,
offsetCenter: [0, '-35%'],
valueAnimation: true,
formatter: function (value) {
return Math.round(value * 100) + '';
},
color: 'inherit'
},
data: [
{
value: 0.7,
name: 'Grade Rating'
}
]
}
]
}
</f:facet>
</pe:echart>
</h:form>
</div>
<div class="card">
<h5>Custom Theme</h5>
<p>Apache ECharts supports custom themes such as the <code>vintage</code> theme in this example, see <a href="https://echarts.apache.org/en/download-theme.html" target="_blank" rel="noopener noreferrer">Apache ECharts Themes</a>. A chart with its own theme does not follow the color scheme of the page.</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/theme/vintage.min.js" integrity="sha512-P+U5OY6oUfmfXUqI9x5V18WdC5ujPMTOZJHC/BZ9nE+rihTUIZnjP1dveK6x3KTVocEW+9xEasqXXjOPciyupg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<h:form id="formThemeUsage">
<p:messages id="messages" showSummary="true" showDetail="true"/>
<pe:echart style="width: 100%; height: 400px;" widgetVar="themeEChart" theme="vintage">
<p:ajax event="itemSelect" listener="#{eChartController.itemSelect}" update="messages"/>
<f:facet name="value">
{
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '70%'],
// adjust the start and end angle
startAngle: 180,
endAngle: 360,
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
]
}
]
}
</f:facet>
</pe:echart>
</h:form>
</div>
<div class="card">
<h5>Export + Print</h5>
<p>The chart can be exported to PNG, JPG or SVG and printed.</p>
<script>
//<![CDATA[
function exportChart() {
//export image
$('#exportOutput').empty().append(PF('exportEChart').exportAsImage());
//show the dialog
PF('exportDlg').show();
};
//]]>
</script>
<h:form id="formExportUsage">
<p:messages id="messages" showSummary="true" showDetail="true"/>
<pe:echart style="width: 100%; height: 400px;" id="echart" widgetVar="exportEChart" value="#{eChartController.json}">
<p:ajax event="itemSelect" listener="#{eChartController.itemSelect}" update="messages"/>
</pe:echart>
<p:commandButton type="button" value="Export" icon="pi pi-home" onclick="exportChart()" styleClass="mr-2 mb-2"/>
<p:commandButton type="button" value="Print" icon="pi pi-print" onclick="PF('exportEChart').print()" styleClass="mr-2 mb-2"/>
</h:form>
<p:dialog widgetVar="exportDlg" showEffect="fade" modal="true" header="Chart as an Image" resizable="false">
<p:outputPanel id="exportOutput" layout="block" style="width: 50vw; height: 400px;"/>
</p:dialog>
</div>
package org.primefaces.extensions.showcase.controller.echarts;
import java.io.Serial;
import java.io.Serializable;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Named;
import org.primefaces.extensions.event.EChartEvent;
@Named
@RequestScoped
public class EChartController implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String json;
@PostConstruct
public void init() {
createJsonModel();
}
public void createJsonModel() {
json = """
{
"title": {
"text": "Apache ECharts Line Chart"
},
"xAxis": {
"type": "category",
"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
},
"yAxis": {
"type": "value"
},
"series": [
{
"name": "Some data",
"data": [150, 230, 224, 218, 135, 147, 260],
"type": "line"
},
{
"name": "Other data",
"data": [110, 260, 124, 118, 235, 100, 200],
"type": "line"
}
],
"legend": {},
"dataZoom": [
{
"type": "slider"
}
]
}\
""";
}
public void itemSelect(EChartEvent event) {
FacesContext facesContext = FacesContext.getCurrentInstance();
String message = "Clicked " + event.getName()
+ ", series index " + event.getSeriesIndex()
+ ", data index " + event.getDataIndex()
+ ", value " + event.getData();
FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, message, null);
facesContext.addMessage(null, facesMessage);
}
public String getJson() {
return json;
}
public void setJson(String json) {
this.json = json;
}
}