MWE: See a graph below with countries in the x-axis. What is the best way to show the whole name in the tooltip instead of the acronym? (Show "Germany" instead of "GER", France instead of "FRA", etc.). I have like 10 or 15 of those.
SEE FULL CODE IN jsfiddle
var example2 = [229, 113, 109];
var labels2 = ["GER", "FRA", "LT"];
https://jsfiddle.net/user3507584/6zpb715x/6/
You can add an object with translations where the key is the value from the label and the value is the full country name:
var example2 = [229, 113, 109];
var labels2 = ["GER", "FRA", "LT"];
var translations = {
GER: 'Germany',
FRA: 'France',
LT: "Italy"
}
var barChartData2 = {
labels: labels2,
datasets: [{
label: 'Student Count',
backgroundColor: '#ccece6',
data: example2
}]
};
function drawChart(el, data, title) {
var ctx = document.getElementById(el).getContext("2d");
var bar = new Chart(ctx, {
type: 'bar',
data: data,
options: {
// Elements options apply to all of the options unless overridden in a dataset
// In this case, we are setting the border of each bar to be 2px wide and green
elements: {
rectangle: {
borderWidth: 2,
borderColor: '#98c4f9',
borderSkipped: 'bottom'
}
},
responsive: true,
legend: {
position: 'bottom',
},
title: {
display: true,
text: title
},
scales: {
yAxes: [{
ticks: {
beginAtZero: 0,
min: 0
}
}],
xAxes: [{
ticks: {
// Show all labels
autoSkip: false,
callback: function(tick) {
var characterLimit = 20;
if (tick.length >= characterLimit) {
return tick.slice(0, tick.length).substring(0, characterLimit - 1).trim() + '...';;
}
return tick;
}
}
}]
},
tooltips: {
callbacks: {
title: function(tooltipItem) {
return translations[tooltipItem[0].xLabel];
}
}
}
}
});
console.log(bar);
};
drawChart('canvas0', barChartData2, 'example title');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.2/Chart.js"></script>
<div id="container">
<canvas id="canvas0"></canvas>
</div>
In this example with universalTransition turned on, after the pie chart of colorBy:'data' is sorted, it is inconsistent with the corresponding relationship between labels and colors in the bar chart, how to make their colors consistent.
Makepie will be out of service on February 15, you can run follow code on ECharts examples editor.
const dataset = {
dimensions: ['name', 'score'],
source: [
['Hannah Krause', 314],
['Zhao Qian', 351],
]
};
const pieOption = {
// dataset: [dataset],
// 顺序排序数据
dataset: [dataset].concat({
transform: {
type: 'sort',
config: { dimension: 'score', order: 'desc' },
},
}),
series: [
{
type: 'pie',
// 通过 id 关联需要过渡动画的系列
id: 'Score',
radius: [0, '50%'],
universalTransition: true,
animationDurationUpdate: 1000,
// 取排序后的数据
datasetIndex: 1,
}
]
};
const barOption = {
dataset: [dataset],
xAxis: {
type: 'category'
},
yAxis: {},
series: [
{
type: 'bar',
// 通过 id 关联需要过渡动画的系列
id: 'Score',
// 每个数据都是用不同的颜色
colorBy: 'data',
encode: { x: 'name', y: 'score' },
universalTransition: true,
animationDurationUpdate: 1000
}
]
};
option = barOption;
setInterval(() => {
option = option === pieOption ? barOption : pieOption;
// 使用 notMerge 的形式可以移除坐标轴
myChart.setOption(option, true);
}, 2000);
Your dataset order by 'desc' on pie chart.
but it's not used on bar chart.
Maybe your two charts should be sorted in the same order
dataset: [dataset].concat({
transform: {
type: 'sort',
config: { dimension: 'score', order: 'desc' },
},
}),
All of the examples here (https://echarts.apache.org/examples/) have hardcoded 'series' objects:
series: [
{
name: 'Forest',
type: 'bar',
data: [320, 332, 301, 334, 390]
},
{
name: 'Steppe',
type: 'bar',
data: [220, 182, 191, 234, 290]
},
{
name: 'Desert',
type: 'bar',
data: [150, 232, 201, 154, 190]
}]
I would like to create these dynamically. Something like this:
for(x=0; x < myData.length; x++){
createSeries(myData[x]);
}
Is that possible?
Sure. Just pass generator to series attribute:
var seriesData = ['Forest', 'Steppe', 'Desert'].map(name => {
return {
name: name,
type: 'bar',
data: Array.from({length: 6}, () => Math.floor(Math.random() * 100)),
}
})
var option = {
//[...]
series: seriesData
//[...]
}
var myChart = echarts.init(document.getElementById('main'));
var seriesData = ['Forest', 'Steppe', 'Desert'].map(name => {
return {
name: name,
type: 'bar',
data: Array.from({length: 6}, () => Math.floor(Math.random() * 100)),
}
})
var option = {
title: {
text: 'ECharts'
},
tooltip: {},
legend: {
data:['Label']
},
xAxis: {
data: ["Category1","Category2","Category3","Category4","Category5","Category6"]
},
yAxis: {},
series: seriesData
};
myChart.setOption(option);
<script src="https://cdn.jsdelivr.net/npm/echarts#4.8.0/dist/echarts.min.js"></script>
<div id="main" style="width: 600px;height:400px;"></div>
P.S. For change series in runtime use myChart.setOption({series: seriesData})
I want to customize the dialog box in jqx scheduler dialog box title. Instead of 'Create new appointment' i want to display "Create a new business schedule".
I work with python django so in the code there are some elements from django template code. So far i create , edit, delete appointments with ajax and django as backend.
var items;
function setAvailability(price_data,persons_data,start_date,end_date, id, a_type, description){
availability_data = {
pk : "{{form.instance.pk}}",
csrfmiddlewaretoken: "{{ csrf_token }}",
price:price_data,
persons:persons_data,
from_date:start_date,
to_date:end_date,
a_type_data:a_type,
av_description:description
}
if(id) {
availability_data['event'] = id;
}
$.ajax({
url: "{% url 'set-availability' %}",
method: "POST",
data: availability_data,
dataType: "json",
success: function(response){
var source = {
datatype: "json",
dataFields: [
{ name: 'id', type: 'integer' },
{ name: 'description', type: 'string' },
{ name: 'location', type: 'string' },
{ name: 'status', type: 'string' },
{ name: 'price', type: 'number' },
{ name: 'persons', type: 'number' },
{ name: 'subject', type: 'integer' },
{ name: 'start', type: 'date', format: "yyyy-MM-dd"},
{ name: 'end', type: 'date', format: "yyyy-MM-dd"}
],
id: 'id',
url: "{% url 'get-availability' %}?pk={{form.instance.pk}}"
};
var adapter = new $.jqx.dataAdapter(source);
$("#scheduler").jqxScheduler({
source: adapter
})
return response;
}
})
}
$.ajax({
url: "{% url 'get-availability' %}",
method: "GET",
data: { pk : "{{form.instance.pk}}" },
dataType: "json",
success: function(response){
items = response;
var source = {
datatype: "array",
dataFields: [
{ name: 'id', type: 'integer' },
{ name: 'description', type: 'string' },
{ name: 'location', type: 'string' },
{ name: 'status', type: 'string' },
{ name: 'price', type: 'number' },
{ name: 'persons', type: 'number' },
{ name: 'subject', type: 'integer' },
{ name: 'start', type: 'date', format: "yyyy-MM-dd"},
{ name: 'end', type: 'date', format: "yyyy-MM-dd"}
],
id: 'id',
localData: items
};
var adapter = new $.jqx.dataAdapter(source);
$("#scheduler").jqxScheduler({
date: new $.jqx.date(2018, 02, 01),
width: 850,
height: 600,
source: adapter,
editDialogDateTimeFormatString: 'yyyy-MM-dd',
editDialogDateFormatString: 'yyyy-MM-dd',
showLegend: false,
localization: { editDialogStatuses: {
available: "Available",
booked: "Booked"
}},
renderAppointment: function(data)
{
if (data.appointment.status == "available") {
data.style = "#B8E6A3";
}
else if (data.appointment.status == "booked") {
data.style = "#FF0013";
}
return data;
},
ready: function () {
$("#scheduler").jqxScheduler('ensureAppointmentVisible', 'id1');
},
resources:
{
colorScheme: "scheme05",
dataField: "id",
source: new $.jqx.dataAdapter(source)
},
appointmentDataFields:
{
id: "id",
description: "description",
location: "location",
subject: "subject",
price: "price",
persons: "persons",
status: "status",
calendar: 'calendar',
from: "start",
to: "end",
},
view: 'monthView',
views:
[
'monthView'
],
renderAppointment: function (dialog, fields, renderAppointment) {
console.info('render appointment:', dialog);
},
editDialogCreate: function (dialog, fields, editAppointment) {
fields.repeatContainer.hide();
fields.subjectContainer.hide();
fields.timeZoneContainer.hide();
fields.colorContainer.hide();
fields.resourceContainer.hide();
fields.allDayContainer.hide();
fields.locationContainer.hide();
fields.fromContainer.hide();
fields.toContainer.hide();
fields.fromLabel.html("Start");
fields.toLabel.html("End");
var priceField = ''
var personsField = ""
priceField += "<div>"
priceField += "<div class='jqx-scheduler-edit-dialog-label'>Price</div>"
priceField += "<div class='jqx-scheduler-edit-dialog-field'><input type='number' id='price' step='0.01' /></div>"
priceField += "</div>"
personsField += "<div>"
personsField += "<div class='jqx-scheduler-edit-dialog-label'>Persons</div>"
personsField += "<div class='jqx-scheduler-edit-dialog-field'><input type='number' id='persons' /></div>"
personsField += "</div>"
var i = 0;
$('#dialogscheduler').children('div').each(function () { // loop trough the div's (only first level childs) elements in dialogscheduler
i += 1;
if (i == 2) { // places the field in the third position.
$(this).after(priceField);
$(this).after(personsField);
};
});
},
editDialogOpen: function (dialog, fields, editAppointment) {
console.info(dialog);
fields.repeatContainer.hide();
}
});
$('#scheduler').on('editDialogOpen', function (event) {
var args = event.args;
var appointment = args.appointment;
if(appointment){
$('#dialogscheduler > div').find('#price').val(appointment.price);
$('#dialogscheduler > div').find('#persons').val(appointment.persons);
}
else {
$('#dialogscheduler > div').find('#price').val(0);
$('#dialogscheduler > div').find('#persons').val(0);
$('#dialogscheduler > div').find('#from').val('');
$('#dialogscheduler > div').find('#to').val('');
$('#dialogscheduler > div').find('#description').val('');
$('#dialogscheduler > div').find('#status').val();
}
});
$('#scheduler').on('appointmentAdd', function (event) {
var price_data = $('#dialogscheduler > div').find('#price').val();
var persons_data = $('#dialogscheduler > div').find('#persons').val();
var a_type = event.args.appointment.status;
var description = event.args.appointment.description;
var start_date = event.args.appointment.from.toString();
var id = null;
var end_date = event.args.appointment.to.toString();
var availability = setAvailability(price_data,persons_data,start_date,end_date,id, a_type, description);
});
$('#scheduler').on('appointmentDelete', function (event) {
var id = event.args.appointment.id;
deleteEvent(id);
});
$('#scheduler').on('appointmentChange', function (event) {
var id = event.args.appointment.id;
var price_data = $('#dialogscheduler > div').find('#price').val();
var persons_data = $('#dialogscheduler > div').find('#persons').val();
var description = event.args.appointment.description;
var a_type = event.args.appointment.status;
var start_date = event.args.appointment.from.toString();
alert(start_date);
var end_date = event.args.appointment.to.toString();
var availability = setAvailability(price_data,persons_data,start_date,end_date,id, a_type,description);
});
}
})
function deleteEvent(pk) {
$.ajax({
url: "{% url 'delete-availability' %}",
method: "GET",
data: { pk : pk, business_pk:'{{form.instance.pk}}'},
dataType: "json",
success: function(response){
console.info(response)
}
})
}
I think you need to put the below code snippet in the editDialogOpen() function. This is working for me.
setTimeout(function() {
dialogRef.find("div").first().find("div").first().html("Create a new business schedule");
}, 10);
You can use the localization to do it. I'm using jqxScheduler with Angular, so:
Add [localization]="localization" into the component definition that should looks like:
<jqxScheduler #scheduler [editDialogCreate]="editDialogCreate" [localization]="localization">
Add a localization property into the component class. jqxScheduler has different titles for create and edit appointents:
localization = {
editDialogTitleString: 'Edit a business schedule',
editDialogCreateTitleString: 'Create a new business schedule'
};
jQWidgets has implementation examples to other languages. JQuery here.
$("#scheduler").jqxScheduler({
localization: {
editDialogCreateTitleString: "Create a new business schedule",
},
});
Is there a way to remove the default sort for the x-axis? It automatically sorts from A-Z but I want to have it as January - December.
Chart Image :
For the missing months for each year and product type, I've auto generated them in PHP(where my final code is). So it would look like:
["January",0,"Apitong","2018","Analog"],["January",0,"Apitong","2018","Digital"],["January",0,"Apitong","2018","Internet"],["February",0,"Apitong","2018","Analog"],["February",0,"Apitong","2018","Digital"], .. etc
My Sample Code: JSFiddle
google.charts.load('current', {
callback: function() {
var data = google.visualization.arrayToDataTable([
['Month', 'Amount', 'Area', 'Year', 'Product Type'],
['January', 3300, 'Apitong', 2015, 'Analog'],
['February', 1000, 'Apitong', 2015, 'Analog'],
['March', 2000, 'Apitong', 2015, 'Analog'],
]);
google.visualization.events.addListener(product, 'ready', drawChart);
function drawChart() {
var areaData = new google.visualization.DataView(area.getDataTable());
var filters = [{
column: 2,
value: area.getState().selectedValues[0]
}
];
// group by 'Group' / 'Year'
var dataGroup = google.visualization.data.group(
areaData, [0, 3], [{
column: 1,
aggregation: google.visualization.data.sum,
type: 'number',
label: 'Sum'
}, {
column: 1,
aggregation: google.visualization.data.count,
type: 'number',
label: 'Count'
}]
);
dataGroup.sort([{
column: 0
}, {
column: 1
}]);
var ColumnChart = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'productssold_chart_div',
'dataTable': view
});
ColumnChart.draw();
}
},
packages: ['controls', 'corechart']
});
when using a Discrete axis ('string' values),
the axis will sort by the order of the rows in the data table
in this case, the rows are set to alphabetical as a result of using static method --> data.group
to correct this issue, an array of month names is used to build a custom sort order
a new column is added to finalData and the index from the array is used as the order
// build final data table
var monthOrder = [
'January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December'
];
var finalData = new google.visualization.DataTable({
cols: [{
label: 'Group',
type: 'string'
}, {
label: 'Amount',
type: 'number'
}, {
label: 'Count',
type: 'number'
}, {
label: 'Sort',
type: 'number'
}]
});
// add row for each month AMOUNT | COUNT
var rowMonth = null;
var rowIndex = null;
for (var i = 0; i < dataGroup.getNumberOfRows(); i++) {
if (rowMonth !== dataGroup.getValue(i, 0)) {
rowMonth = dataGroup.getValue(i, 0);
rowIndex = finalData.addRow();
finalData.setValue(rowIndex, 0, rowMonth);
}
for (var x = 1; x < finalData.getNumberOfColumns(); x++) {
switch (finalData.getColumnLabel(x)) {
case 'Amount':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 2).toString());
break;
case 'Count':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 3).toString());
break;
case 'Sort':
finalData.setValue(rowIndex, x, monthOrder.indexOf(rowMonth));
break;
}
}
}
finalData.sort([{column: 3}]);
see following working snippet...
google.charts.load('current', {
callback: function() {
var data = google.visualization.arrayToDataTable([
['Month', 'Amount', 'Area', 'Year', 'Product Type'],
['February', 1000, 'Apitong', 2015, 'Analog'],
['February', 1700, 'Apitong', 2015, 'Internet'],
['February', 1200, 'Avenida Veteranos', 2015, 'Digital'],
['February', 2800, 'Brgy. Baras', 2015, 'Internet'],
['February', 2150, 'Avenida Veteranos', 2018, 'Digital'],
['February', 2700, 'Apitong', 2018, 'Internet'],
['February', 2500, 'Brgy. Baras', 2018, 'Internet'],
['March', 2000, 'Apitong', 2015, 'Digital'],
['March', 2400, 'Avenida Veteranos', 2015, 'Digital'],
['March', 1600, 'Brgy. Baras', 2015, 'Internet'],
['March', 3000, 'Avenida Veteranos', 2018, 'Analog'],
['March', 1400, 'Apitong', 2018, 'Digital'],
['January', 3300, 'Avenida Veteranos', 2015, 'Analog'],
['March', 2000, 'Brgy. Baras', 2018, 'Analog'],
['January', 2600, 'Brgy. Baras', 2015, 'Internet'],
['January', 1800, 'Apitong', 2015, 'Digital'],
['January', 2100, 'Brgy. Baras', 2015, 'Analog']
]);
var area = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_productssold_area_div',
'dataTable': data,
'options': {
'filterColumnLabel': 'Area',
'ui': {
'allowTyping': false,
'allowMultiple': false,
'allowNone': false,
'sortValues': false,
'label': 'Choose Area',
}
}
});
var year = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_productssold_year_div',
'dataTable': data,
'options': {
'filterColumnLabel': 'Year',
'ui': {
'allowTyping': false,
'allowMultiple': false,
'allowNone': false,
'sortValues': false,
'label': 'Choose Year',
}
}
});
var product = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'filter_productssold_product_div',
'dataTable': data,
'options': {
'filterColumnLabel': 'Product Type',
'ui': {
'allowTyping': false,
'allowMultiple': true,
'allowNone': true,
'sortValues': false,
'label': 'Choose Product',
}
}
});
google.visualization.events.addListener(area, 'ready', drawChart);
google.visualization.events.addListener(area, 'statechange', drawChart);
google.visualization.events.addListener(year, 'ready', drawChart);
google.visualization.events.addListener(year, 'statechange', drawChart);
google.visualization.events.addListener(product, 'ready', drawChart);
google.visualization.events.addListener(product, 'statechange', drawChart);
function drawChart() {
var areaData = new google.visualization.DataView(area.getDataTable());
var filters = [{
column: 2,
value: area.getState().selectedValues[0]
}
];
var selectedYear = year.getState().selectedValues;
if (typeof selectedYear !== 'undefined' && selectedYear.length > 0) {
filters.push({
column: 3,
test: function(value, row, column, table) {
return (selectedYear.indexOf(table.getValue(row, column)) > -1);
}
});
}
var selectedProducts = product.getState().selectedValues;
if (typeof selectedProducts !== 'undefined' && selectedProducts.length > 0) {
filters.push({
column: 4,
test: function(value, row, column, table) {
return (selectedProducts.indexOf(table.getValue(row, column)) > -1);
}
});
}
areaData.setRows(areaData.getFilteredRows(filters));
// group by 'Group' / 'Year'
var dataGroup = google.visualization.data.group(
areaData, [0, 3], [{
column: 1,
aggregation: google.visualization.data.sum,
type: 'number',
label: 'Sum'
}, {
column: 1,
aggregation: google.visualization.data.count,
type: 'number',
label: 'Count'
}]
);
dataGroup.sort([{
column: 0
}, {
column: 1
}]);
// build final data table
var monthOrder = [
'January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December'
];
var finalData = new google.visualization.DataTable({
cols: [{
label: 'Group',
type: 'string'
}, {
label: 'Amount',
type: 'number'
}, {
label: 'Count',
type: 'number'
}, {
label: 'Sort',
type: 'number'
}]
});
// add row for each month AMOUNT | COUNT
var rowMonth = null;
var rowIndex = null;
for (var i = 0; i < dataGroup.getNumberOfRows(); i++) {
if (rowMonth !== dataGroup.getValue(i, 0)) {
rowMonth = dataGroup.getValue(i, 0);
rowIndex = finalData.addRow();
finalData.setValue(rowIndex, 0, rowMonth);
}
for (var x = 1; x < finalData.getNumberOfColumns(); x++) {
switch (finalData.getColumnLabel(x)) {
case 'Amount':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 2).toString());
break;
case 'Count':
finalData.setValue(rowIndex, x, dataGroup.getValue(i, 3).toString());
break;
case 'Sort':
finalData.setValue(rowIndex, x, monthOrder.indexOf(rowMonth));
break;
}
}
}
finalData.sort([{column: 3}]);
var view = new google.visualization.DataView(finalData);
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}, 2, {
calc: 'stringify',
sourceColumn: 2,
type: 'string',
role: 'annotation'
}]);
var ColumnChart = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'productssold_chart_div',
'dataTable': view
});
ColumnChart.draw();
}
area.draw();
year.draw();
product.draw();
},
packages: ['controls', 'corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="filter_productssold_area_div"></div>
<div id="filter_productssold_year_div"></div>
<div id="filter_productssold_product_div"></div>
<div id="productssold_chart_div"></div>