jquery prevent multiple instances of plugin - javascript

I am trying to display and update a chart using the plugin http://workshop.rs/jqbargraph/. The plugin is initiated on page load but I need to allow users to update the data that powers the chart. However, this functionality adds multiple charts everytime the update event is initiated. I assume I need to somehow destroy the original instance of the plugin before updating the chart data and re-initiating it but there is nothing incorporated into the plugin to allow this.
Can anyone tell me what I need to add to my code to get this working?
jQuery( document ).ready(function() {
var chartData = new Array([0]);
showChart(chartData);
jQuery('#update').live("click", function() {
var qtyArr = [];
jQuery('input[name=qty]').each(function(i) {
qty = Number(jQuery(this).val());
if(qty > 0){
qtyArr.push(qty);
}
});
chartData = new Array(
[qtyArr]
);
showChart(chartData);
});
});
function showChart(chartData){
jQuery("#chart").jqBarGraph({
data: chartData,
width: 200,
height: 300
});
}

call empty() before you call the plugin:
jQuery("#chart").empty().jqBarGraph({
data: chartData,
width: 200,
height: 300
});

The plugin's demo page clears the chart and reinitialises it as follows :
$('#exampleSimple').html('');
$('#exampleSimple').jqbargraph({ data: arrayOfData });
.empty() should also work.
You probably want -
function showChart(chartData) {
$('#chart').empty().jqBarGraph({
data: chartData,
width: 200,
height: 300
});
}

Related

Make events run multiple times, Highcharts

I have a Highchart in which under the options object I have events object as ashown below.
var options = {
chart: {
renderTo: 'container',
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
var series = this.series[0],
chart = this;
...// Some Code
}
}
So what I want is that I need events data to update dynamically and load the Highcharts only once.
How can I make the Following section dynamic so that the values in it change dynamically. Keeping in mind that Highcharts container have to be defined and load only once.
events: {
load: function() {
var series = this.series[0],
chart = this;
...// Some Code
}
}
One of the official Highcharts demos shows how to achieve it. Take a look at it:
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/dynamic-update/
Highcharts also offers other options to update the chart with new data, API:
https://api.highcharts.com/class-reference/Highcharts.Chart#addSeries
https://api.highcharts.com/class-reference/Highcharts.Series#update
https://api.highcharts.com/class-reference/Highcharts.Series#setData

Ziggeo meta-profiles parameter for recording video in javascript

I've been playing around with the ziggeo API and I'm trying to attach some events for a recording. as far as I can tell, the best way to do this is to create a div with a specific id and then create the ziggeo recorder using attribs, etc.
<div id="video_section"></div>
<script>
ZiggeoApi.Events.on("system_ready", function() {
var recorder = new ZiggeoApi.V2.Recorder({
element: document.getElementById("video_section"),
attrs: {
width: 320,
height: 240,
theme: "modern",
themecolor: "red",
}
});
recorder.activate();
});
</script>
yet, unlike the use of the simple form <ziggeorecorder></ziggeorecorder> which allows the passing of a meta-profile parameter,
<ziggeorecorder ziggeo-theme='minimalist' ziggeo-themecolor="red" ziggeo-meta-profile='META_PROFILE_TOKEN'></ziggeorecorder>
when adding meta-profile in the attribs, initializing the recorder (as indicated in the API reference) results in meta-profile being misinterpreted. when changing the attribute to meta_profile, nothing gets processed.
attrs: {
width: 320,
height: 240,
theme: "modern",
themecolor: "red",
meta_profile: 'META PROFILE ID',
}
beyond that, when trying to attach the event.
<script>
var element = document.getElementById('video_section');
var embedding = ZiggeoApi.V2.Recorder.findByElement(element);
embedding.on("submitted", function(data) {
alert("Video " + data.video.token + " was submitted!");
});
</script>
I keep getting an error:
Uncaught TypeError: Cannot read property 'on' of null
does anyone have a good grip on how to do this properly? - create a recorder, set a meta-profile, and attach an event (either submission or completion of processing) to redirect back to a root path.
I think you need to use meta-profile instead of meta_profile. You may try this code:
<div id="video_section"></div>
<script>
ZiggeoApi.Events.on("system_ready", function() {
var recorder = new ZiggeoApi.V2.Recorder({
element: document.getElementById("video_section"),
attrs: {
width: 320,
height: 240,
theme: "modern",
themecolor: "red",
"meta-profile":"META PROFILE ID"
}
});
recorder.activate();
recorder.on("verified", function(data){
console.log(data);
});
});
</script>
Javascript doesn't allow using - outside quote when defining object property (CMIIW).

c3.js set onClick property in chart generated from another function

My goal is to get 3 charts, with the most recently selected series in the first chart updating the second chart, and the most recently selected series in the second chart updating the third chart.
I start by setting up 3 divs:
<div id="chart1"></div>
<div id="chart2"></div>
<div id="chart3"></div>
I then generate 3 charts like so (essentially the same, but with different detail levels in the source data):
var chart1 = c3.generate({
bindto: document.getElementById('chart1'),
data: {
x: 'date',
url: 'file1.csv'
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d',
count: 8
},
label: "Date"
},
y: {
label: "Y Label"
}
},
// irrelevant options removed
legend: {
item: {
onclick: (id) => {
chart1.toggle(id);
chart_options2.data.url = 'file2_'+ id +'.csv';
if(chart1.data.shown(id).length == 1 ){
generateChart2(id);
}
}
}
}
});
var chart2 = c3.generate({
bindto: document.getElementById('chart2'),
// etc.
var chart3 = c3.generate({
bindto: document.getElementById('chart3'),
// etc.
The function generateChart2() will use the id of the selected series in chart1 to generate a new chart in the place of chart2. Likewise I have a similar function generateChart3() which will use the id of the selected series in chart2 to generate a new chart in the place of chart3. These functions look like this:
function generateChart2(id) {
c3.generate(chart_options2);
};
With chart_options being identical to the original set up options, except for the updated file source (see chart_options2.data.url = 'file2_'+ id +'.csv'; above).
Initially, these all seem to work ok. The problem arises when a new chart2 is created using the generateChart2() function, and the onclick property no longer seems to work for certain things. Testing with console.log, the onclick still seems to be called, and I can update the chart options var, but I can't use any of the other commands:
onclick: function (id) {
console.log('test'); // returns 'test'
chart2.toggle(id); // doesn't work
chart_options3.data.url = 'file3_'+ id +'.csv'; // works
if(chart2.data.shown(id).length == 1 ){
generateChart3(id); // doesn't work
}
I suspect it has something to do with the namespace, or how I'm using the chart names, or how I'm calling the function. I've spent a couple of days looking at this problem, but all my research hasn't really made it much clearer which direction I should be looking in.
EDIT: I found a workaround, which makes sense for my use case, but doesn't help me learn what I was doing wrong. Now instead of reusing c3.generate to dynamically create a new chart every time a series is selected in the previous chart, I am using unload() and load(). This seems to be working well, but I would very much appreciate an explanation or clarification of what I was doing wrong the first time. Updated code:
onclick: function (id) {
chart1.toggle(id);
if(chart1.data.shown(id).length == 1 ){
chart2.unload();
setTimeout(function () {
chart2.load({
url: 'file2_'+ id +'.csv'
});
}, 1000);
}
}

How do you get a Google Chart to redraw based on data you pass to it?

The bulk of the examples I've found showing Google Charts have simple little arrays...
I need to pull an array from my server.
I can get a pie chart to draw, but it doesn't update.
Here is my attempt to get a flexible, redrawing pie chart:
At the top of my javascript, but before document.ready:
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
My drawChart function:
function drawChart(arrFeedbackResult3) {
console.log('Draw a fucking chart ... ') + console.log(arrFeedbackResult3);
var chart_data = new google.visualization.DataTable(arrFeedbackResult3);
var options = {
title: 'Comments by Group',
sliceVisibilityThreshold: 1/20, // Only > 5% will be shown.
width: 400,
height: 400
};
chart = new
google.visualization.PieChart(document.getElementById('groupPieChartDiv'));
chart.draw(chart_data, options);
// chart = new google.visualization.PieChart(document.getElementById('groupPieChartDiv'));
// chart.draw(data, options);
}
And the function that, after a button is clicked, passes fresh data to drawChart:
function setupFeedback3(arrFeedbackResult3){ // Create Group summary Graphs
console.log('Groups summary from DB: ') + console.log(arrFeedbackResult3);
drawChart(arrFeedbackResult3);
} // END setupFeedback3
I get a "table has no columns" message on my page with the above code.
The array, arrFeedbackResult3, is formatted correctly and does render a chart when I change the code but end up without the ability to refresh.
Any help appreciated. I think I'm just missing the basic flow of using Google Charts...and how/where the callback should be used.
Updating with my next attempt after a very generous and detailed reply.
My js is in a separate file from the html. I cannot get the passing of an array via callback to work. I get "not a constructor" errors or "not a function." I think because adding a parenthetical value breaks the code.
I also don't understand the comment about document.ready in the answer...I have kept document.ready in order to load all my other functions.
Right after document.ready I have:
google.charts.load('current', {
packages:['corechart'],
callback: drawChart
});
Then, after my db POST to get data, I call:
function setupFeedback3(result){ // Create Group summary Graphs
arrFeedbackResult3 = result; //Store in global variable for access by chart
drawChart();
} // END setupFeedback3
arrFeedbackResult3 is a GLOBAL variable - only way I could get the data to the draw chart function.
Then:
function drawChart() {
console.log('Draw a chart ... ') + console.log(arrFeedbackResult3);
// var chart_data = new google.visualization.DataTable(arrFeedbackResult3);
var chart_data = google.visualization.arrayToDataTable(arrFeedbackResult3);
var options = {
title: 'Comments by Group',
sliceVisibilityThreshold: 1/20,
width: 400,
height: 400
};
var chart = new google.visualization.PieChart(document.getElementById('groupPieChartDiv'));
chart.draw(chart_data, options);
}
This is working, and the chart does update as you feed different data, but it seems a shoddy state of affairs. One specific example of passing data, vs. a stupid simple example or using AJAX inside the function, would have been really helpful.
first, recommend not using jsapi to load the library.
according to the release notes...
The version of Google Charts that remains available via the jsapi loader is no longer being updated consistently. Please use the new gstatic loader.js from now on.
<script src="https://www.gstatic.com/charts/loader.js"></script>
this will only change the load statement...
google.charts.load('current', {packages:['corechart']});
next, the callback can be added to the load statement...
google.charts.load('current', {
packages:['corechart'],
callback: drawChart
});
or you can use the promise it returns...
google.charts.load('current', {
packages:['corechart']
}).then(drawChart);
also, the load statement will wait until the document is ready by default,
so it can be used in place of --> $(document).ready
finally, when creating a data table,
the argument for the constructor should be JSON, not a simple array
see Format of the Constructor's JavaScript Literal data Parameter,
for the specific JSON format
if you want to create a data table from a simple array,
use static method --> arrayToDataTable
recommend setup similar to following...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
// get data
drawChart(arrayData);
});
function drawChart(arrayData) {
var chart_data = google.visualization.arrayToDataTable(arrayData);
var options = {
title: 'Comments by Group',
sliceVisibilityThreshold: 1/20,
width: 400,
height: 400
};
var chart = new google.visualization.PieChart(document.getElementById('groupPieChartDiv'));
chart.draw(chart_data, options);
}
function setupFeedback(arrayData) {
// get data
drawChart(arrayData);
}
UPDATE
you can use the promise the load statement returns as the callback and the document ready
just move the code as shown below...
then you can load your ajax call to get the data
google.charts.load('current', {
packages:['corechart']
}).then(function () {
// move code from document ready here
// get data
getData();
});
function getData() {
$.ajax({
type: 'POST',
contentType: 'application/json',
url: sourceURL,
success: setupFeedback
});
}
function setupFeedback(result) {
// you could draw the chart here
// just move the code from drawChart
// or pass the data along to another function
drawChart(result);
}
function drawChart(result) {
var chart_data = google.visualization.arrayToDataTable(result);
var options = {
title: 'Comments by Group',
sliceVisibilityThreshold: 1/20,
width: 400,
height: 400
};
var chart = new google.visualization.PieChart(document.getElementById('groupPieChartDiv'));
chart.draw(chart_data, options);
}

The setOptions() does not work on a chart in a ChartWrapper after I run the ChartEditor

I have a chart in a wrapper:
var wrapper9 = null;
var chartcolors09 = parent.defaultcolors;
var chartEditor9 =null;
function Chart9() {
var data = new google.visualization.DataTable(<?=$jsonTableB9?>);
wrapper9 = new google.visualization.ChartWrapper({
chartType:'BarChart',
dataTable: data,
options: {
'colors': chartcolors09,
'chartArea': {
'left': 40,
'top': 50,
'right': 100,
'bottom': 50
},
'legend' :'Right',
'title':'Chart Title'
}
});
}
I can run a function to update colors of that chart using this function:
function setcolor9(){
wrapper9.setOptions({
'colors': chartcolors09
});
wrapper9.draw(document.getElementById('chart_div9'));
}
and this works just fine. I can also use other functions on that chartin that wrapper to update some other options. BUT when I use the ChartEditor on this chart
function loadEditor9() {
chartEditor9 = new google.visualization.ChartEditor();
google.visualization.events.addListener(chartEditor9, 'ok', redrawChart9);
chartEditor9.openDialog(wrapper9, {});
}
function redrawChart9(){
chartEditor9.getChartWrapper().draw(document.getElementById('chart_div9'));
}
the setcolor9() function stops working. It kinda looks like the ChartEditor created a 2nd chart and put it on top of the first one and the setcolor9() function keeps referring to the first one.
...oh and not sure if this is connected but the chart created by the loadEditor9() and redrawChart9() functions seems to ignore the height and width options set by other functions in the wrapper9 var and goes "outside" of the div container.
So the answer is of course very simple.
I just needed to change the redrawChart9() function to the below and now I can do whatever I want with that chart.
function redrawChart9(){
wrapper9 = chartEditor9.getChartWrapper();
wrapper9.draw();
}

Categories

Resources