jqPlot: possible to dynamically add a new series? - javascript

Is it possible to dynamically add a new series to an existing jqPlot object?
I have a jqPlot object that uses the AJAX data renderer to retrieve 2 series. This part works works fine.
Based on user input (and several parameters), I would like to be able to dynamically add or remove additional series to the chart (while keeping the two original).
Is this possible? Is it possible without having to retrieve the unchanged data for the original two lines again?
Alternatively, if this is not possible, are there any recommendations for a different charting library that can do this?

Yes it is, I just found out how to do this, and I found your question, and there was no answer, so I will provide mine. Now, this is probably not the most elegant way to do it, but it works.
$(document).ready( function () {
DataSeriesToPlot = [[[x1_1,y1_1],[x1_2,y1_2]],[[x2_1,y2_1],[x2_2,y2_2]],
[[x3_1,y3_1], [x3_2,y3_2]]];
AxesOptions = {
xaxis: {min: xmin, max: xmax},
yaxis: {min: ymin}
};
PlotTitle = 'PlotTitle',
PlotSeriesDefaults = {
showMarker: false,
shadow: false,
rendererOptions: {
smooth: true
}
};
PlotLegend = {
show: true,
labels: ['label1','label2','label3']
};
PlotSeriesOptions = [
{
linePattern: 'dashed',
color: '#f80202',
},
{
linePattern: 'dashed',
color: '#f80202',
},
{
color: '#f80202',
}
];
PlotVar = $.jqplot('Plotdiv', DataSeriesToPlot,
{
axes: AxesOptions,
title: PlotTitle,
seriesDefaults: PlotSeriesDefaults,
series: PlotSeriesOptions,
legend: PlotLegend
});
AddToPlot();
});
function AddToPlot(){
$("Plotdiv").empty();
DataSeriesToPlot.push([[x4_1,y4_1],[x4_2,y4_2]]);
PlotLegend.labels.push('label4');
PlotSeriesOptions.push({
linePattern: 'dashed',
color: '#ff6600',
});
PlotVar = $.jqplot('Plotdiv', DataSeriesToPlot,
{
axes: AxesOptions,
title: PlotTitle,
seriesDefaults: PlotSeriesDefaults,
series: PlotSeriesOptions,
legend: PlotLegend
});
}

Related

ApexChart: Line chart another option

Hi I am using АpexChart but I have problem setting up xaxis. The picture below is from another chart, but I'm looking for the effect it has. Note the long straight line, this means there is no data for the specific period.
How do I set up a АpexChart so I can display similar data
var options = {
series: [{
name: "Level",
data: [30,45,50,60,70,91,125]
}],
chart: {
height: 350,
type: 'line',
zoom: {
enabled: true
}
},
dataLabels: {
enabled: true
},
stroke: {
curve: 'straight'
},
title: {
text: 'Battery',
align: 'left'
},
grid: {
row: {
colors: ['#f3f3f3', 'transparent'], // takes an array which will be repeated on columns
opacity: 0.5
},
},
xaxis: {
categories: [1991,1992,1993,1994,1995,1996,1997, 1998,1999]
}
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
The chart we see on your screenshot has been made with Highcharts, right? I know that you can do something similar with amCharts or Chart.js. But this feature is not available in ApexCharts yet. With ApexCharts, you will get blanks (see demo) if you have null values in your data.
Take a look at this issue and this pull request on GitHub.
Comment of the library author (2019), from the issue:
This has been proposed, but not worked upon yet.
Comment of the library author (2021), from the PR:
Update: This PR doesn't solve the issue the way we wanted and doesn't cover multiple use-cases.
Please bear with us. There might be a new PR with a completely different implementation.

Chart.js - Mouseover causes graphs to flicker and resize

To start, I have made a short video to show exactly what I'm running into.
To summarize the video: while using Chart.js (2.6.0), I can create my charts without issue; but when I mouse-over the bars/points, the chart will resize its elements and flicker. The weird thing is that it's totally inconsistent. Sometimes when I refresh, it doesn't have this behaviour at all; but if I hover over something and it starts doing it, it won't stop until I refresh again or close out of the tab (it is inconsistent with this, also). I don't change anything in the code when this occurs, it does this all on its own.
In an attempt to fix it, I've referenced many other threads here on SO, as well as the Chart.js documentation. Among my solutions: I have made a point to add in a specified Height/Width to the Divs & Canvas creating the graphs; Set the Animation duration to 0, the Hover Animation duration to 0, and the Responsive Animation duration to 0; I've ensured that Responsive is set to true, and have kept Maintain Aspect Ratio as true, changed the tooltip mode... I've tried all of these, among other little things that seem to have little-to-no effect.
I'm stumped!
Here is one of my charts' code (without how I'm grabbing the JSON data etc, just the Chart):
new Chart($("#runwayChart"), {
type: "horizontalBar",
data: {
labels: runwayLabels,
datasets: [{
label: "Months Left", fill: true,
backgroundColor: "#3333ff",
borderColor: "#3333ff",
data: score
}, {
label: "Expenses",
fill: true,
backgroundColor: "#aa2222",
borderColor: "#aa2222",
data: expenses
}, {
label: "Revenue",
fill: true,
backgroundColor: "#2222aa",
borderColor: "#2222aa",
data: revenues
}]
},
options: {
tooltips: {
mode: 'index'
},
responsive: true,
maintainAspectRatio: true,
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0
}
});
I'd appreciate any help you all may have!
Thanks =)
I see that it has been a while since somebody wrote an answer to this post. I solved my flickering issue by applying two things.
First one
When I declare the chart I use:
var ctx = document.getElementById('chart').getContext('2d');
window.chart = new Chart(ctx, {}) ...
rather than var chart = new Chart(ctx, {})..
In this way, we make sure that the chart has been appended to the window. object.
Secondly
Before drawing the new diagram (For example for data update) we need to make sure that the previous canvas has been destroyed. And we can check that with the code below:
if(window.chart && window.chart !== null){
window.chart.destroy();
}
It was actually a really simple, and odd solution.
When the data point was near the top of the chart, the chart would try to resize depending on the div. As the chart lived in a larger canvas, putting inside its own div solved this issue.
<div>
<canvas id="chart"></canvas>
</div>
Formatting it like this was the solution =)
Try This :
var myLineChart = null;
function createChart() {
var ctx1 = document.getElementById("barcanvas").getContext("2d");
myLineChart = new Chart(ctx1, {
type: 'horizontalBar',
data: {
labels: runwayLabels
, datasets: [{
label: "Months Left"
, fill: true
, backgroundColor : "#3333ff"
, borderColor: "#3333ff"
, data: score
}, {
label: "Expenses"
, fill: true
, backgroundColor : "#aa2222"
, borderColor: "#aa2222"
, data: expenses
}, {
label: "Revenue"
, fill: true
, backgroundColor : "#2222aa"
, borderColor: "#2222aa"
, data: revenues
}]
}
options:
{
scales: {
xAxes: [{
ticks: {
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: {
// We'll edit the `title` string
title: function (tooltipItem) {
// `tooltipItem` is an object containing properties such as
// the dataset and the index of the current item
// Here, `this` is the char instance
// The following returns the full string
return this._data.labels[tooltipItem[0].index];
}
}
},
title:
{
display: true,
text: "Your Chart Title"
},
responsive: true,
maintainAspectRatio: true
}
});
}
I had the same issue with my angular application(angular v6 and chartjs 2.9.4).
After adding delay and destroying the chart instance before redrawing the chart resolved my issue.
public redraw() {
setTimeout(() => {
if (this.chart && this.chart != null) {
this.chart.destroy()
}
this.chart = new Chart(this.chartId, this.chartConfig);
}, 500);
}

Different tooltips for series in FlotChart

I have Flot line chart with two dataseries. I would like to edit the tooltips independently for each series. I have tried moving the tooltip settings to the dataset part but it didn't work.
Does anyone know a solution?
$(function () {
var barOptions = {
xaxis: {
tickDecimals: 0
},
yaxes: [{
position: "left"
}, {
position: "right"
}],
colors: ["#36c6d3"],
grid: {
color: "#888888"
},
tooltip: {
show: true,
content: "Uge %x, %s: %y"
}
};
var dataset = [{
data: occData.data,
label: occData.label,
yaxis: occData.yaxis,
lines: {
show: true,
lineWidth: 1,
}
}, {
data: houseData.data,
label: houseData.label,
yaxis: houseData.yaxis,
color: 'grey',
lines: {
show: true,
lineWidth: 1,
fill: false
}
}];
$("#flot-line-chart-past").plot(dataset, barOptions);
});
I'm going to presume that you are using flot.tooltip to provide the tooltips. In which case, the content property of the tooltip configuration object can be a function as well as a format string. I quote from the documentation for the plug-in:
you can pass a callback function(label, xval, yval, flotItem) that must return a string with the format described.
So write a function that distinguishes between each label you use for the two series, and return a different format string for each.

javascript highcharts builder function

I am trying to make a function which will be building Highcharts charts dynamically based on parameters passed. I do it the following way:
function makeChart(name, title, series)
{
var options = {
chart: {
type: 'areaspline',
renderTo: name
},
credits: { enabled: false },
legend: { enabled: true },
title: {
text: title
},
xAxis: {
type: 'datetime'
},
yAxis: {
gridLineDashStyle: 'dot',
title: {
text: 'Quantity'
}
},
plotOptions: {
areaspline: {
animation: false,
stacking: '',
lineWidth: 1,
marker: { enabled: false }
}
},
series: [] //chart does not display except title. It will draw if I paste the data here manually
};
this.chart = new Highcharts.Chart(options);
for (index = 0; index < series.length; ++index) {
options.series[index] = {'name':series[index][0], 'data':series[index][1], 'color':series[index][2], 'fillOpacity': .3};
}
}
makeChart('container2', 'second chart', [['thisisname1', [20,21,22,23,24,25,26,27,28], '#d8d8d8']]);//calling function with test parameters
But everything I can see is the charts title. I guess the problem is in adding data to series array. I tried to add it with several ways but it did not work, although I see that the data has been added if I console.log(options.series). Any ideas how to fix that? Thank you.
Place this.chart = new Highcharts.Chart(options); after the for loop.
You're adding the data after the chart has been initialized, for it to work this way you need to tell HighCharts to redraw itself, easier option is to init after the loop. :)

Way to shorten / refactor multiple plugin values

I have some 15-20 highcharts on a single page (using a slider, 1-2 charts per slide), some bar charts, some column charts, some pie charts, with different display options. What I was using was having multiple methods inside my closure where I had methods like self.drawColumnChart(xPlotColor, yPlotColor, xPlotLabelSize, yPlotLabelSize, ...10 more arguments). Inside the same object I have methods like 'drawRevenueChart(), drawLossChart()' etc. drawRevenueChart() was calling self.drawColumnChart( with 15 arguments. As the number of charts grew, I ended up passing more and more arguments to self.drawColumnChart( so I thought I could refactor this by changing the drawRevenueChart() as
("$id").highcharts(
{chart: {
plotOptions: {
labelSize: '2em'
},
xAxis:{
labelSize: '1.3em',
formatter: function(){
return '% ' + this.value;
}
...and so on
}
})'
I don't need the self.drawColumnChart(xPlotColor, yPlotColor, xPlotLabelSize, yPlotLabelSize, ...10 more arguments) any more but I just passed that complexity to drawRevenueChart(). drawRevenueChart() used to be 2 lines long, but now it's 25 lines long. Same with drawLossChart(), it used to be 3 lines long, just calling self.drawColumnChart(, but it turned into a 15 line long method after refactor.
Can you guys think of any other way how I can refactor/shorten this? Maybe drawRevenueChart() calls self.drawChart("column", [plotOptions.labelSize: '2em', xAxis: {labelSize: '1.e em'}...
It just seems that I have to keep repeating
plotOptions: {
labelSize: '2em'
},
xAxis:{
labelSize: '1.3em',
all over my closure for each chart with different options. Is there a way to shorten this? I'm already using jQuery extend() to extend default chart options with custom options. It's all inside a closure. But regardless of how I refactor this, I find myself repeating the same lines with different options. Any ideas are welcome.
Update:
As requested by TrueBlueAussie:
it used to be:
myClosure{
var self = this;
self.drawColumnChart = function(selector, xPlotColour, yPlotColour, xAxisName, yAxisName, xPlotOptionsSize....10 more arguments)
{
$(selector).highcharts({
chart: {
type: 'column'
},
xPlot:{
style:{
color: xPlotColour
}
},
yPlot: {
labels: {
style:{
color: yPlotColour
}
}
},
xAxis:{
labels: {
name: xAxisName,
}
}
})
}
drawRevenueChart: function(data){
self.drawColumnChart("#chartid1", 'blue', 'red', 'profit', 'month', '1.2em', null, false, null....);
}
drawLossChart: function(data){
self.drawColumnChart("#chartid2", 'orange', 'yellow, 'loss', 'month', '2em' ...);
}
}
After refactor
drawRevenueChart: function(data){
$("#chartid1").highcharts({
chart: {
type: 'column'
},
xPlot:{
style:{
color: 'blue'
}
},
yPlot: {
labels: {
style:{
color: 'red'
}
}
},
xAxis:{
labels: {
name: 'profit',
}
}
});
}
drawLossChart: function(data){
$("chartid2").highcharts({
xplot:{
style:{
color: 'orange'
}
},
xAxis:{
labels:{
name: 'loss',
color: 'puke'
}
}
}
};
So I just moved the 3 level deep object setting from one method to another, no real gain.
Okay, that is clearer now. This is not really a code refactoring problem, so much as a data-refactoring problem. The only solution I can suggest is to find common data in the structures, store those branches as vars within your scope and $.extend() them together to build the final options structure.
e.g.
myClosure {
// Put any common settings in shared vars
var columnChart = {
chart: {
type: 'column'
}
// any other common properties for a column chart
};
var barChart = {
chart: {
type: 'barchart'
}
// any other common properties for a bar chart
}
var self = this;
self.drawColumnChart = function (selector, data) {
$(selector).highcharts($.extend({}, columnChart, data));
}
drawRevenueChart: function (data) {
self.drawColumnChart("#chartid1", {
xPlot: {
style: {
color: 'blue'
}
},
yPlot: {
labels: {
style: {
color: 'red'
}
}
},
xAxis: {
labels: {
name: 'month name',
}
}
});
}
drawLossChart: function (data) {
self.drawColumnChart("#chartid2", {
xPlot: {
style: {
color: 'orange'
}
},
yPlot: {
labels: {
style: {
color: 'yellow'
}
}
},
xAxis: {
labels: {
name: 'loss',
}
});
}
}
}
This has the advantage that each call is still readable, if you know the HighCharts option structure, and is therefore easier to maintain.
Unless you use a strongly typed JS language (like TypeScript), using functions with loads of parameters is human-error-prone so best avoided.
What I ended up doing is I created an object inside the plugin which handles all the highcharts options with a single drawChart function which takes an object. i.e.
var plugin = function(){
helper.drawChart({
legendEnabled: true,
selector: '#divID',
backgroundColor: '#FF0000', //etc all other options
});
var chartHelper = function(){
var defaults = {
_common:{
//common highcharts options
{
legend: false //etc
}
},
_bar:{
chart: 'bar', //all common bar options
},
get bar(){ return $.extend({}, _common, _bar); }
}
this.drawChart = function(options){
var default = {};
if (options.legendEnabled){
default.legend = true;
}
if (options.yLabelText){
default.yTitle = { text = options.yLabelText }
}//and other options here
$(options.selector).highchart($.extend({}, defaults.bar, default);
}
}
var helper = new chartHelper();
}
I have some 20 charts inside the plugin and this saved me some 600 lines. All the chart logic is inside the helper, it doesn't clutter the plugin code, I don't need to keep repeating .highcharts({ 20 different options }) inside each draw function, it's just once I need to do that now.

Categories

Resources