I try to get data from the API and refresh the Pie chart on an Electron application page, but I can't refresh the value of the chart. The values on the chart never change. I tried this method with RGraph Gauge before and it worked, but with Electron doesn't refresh the value. What am I doing wrong? Thank you for your help.
Screenshot of my electron application
<script>
const ipcRenderer = require("electron").ipcRenderer;
const {session} = require('electron').remote;
document.getElementById("backBtn").addEventListener("click",()=>{
ipcRenderer.send("btnBack","101");
});
temp = new RGraph.HorseshoeMeter({
id: 'temp',
min: 0,
max: 50,
value: 15,
options: {
colors: ["#3678c1", '#BED1E3'],
textColor: "#3678c1",
animationOptions: {frames: 60} // Doesn't need to be a string
}
}).draw();
hum = new RGraph.HorseshoeMeter({
id: 'hum',
min: 0,
max: 100,
value: 45,
options: {
colors: ["#3678c1", '#BED1E3'],
textColor: "#3678c1",
animationOptions: {frames: 60} // Doesn't need to be a string
}
}).draw();
iaq = new RGraph.HorseshoeMeter({
id: 'iaq',
min: 0,
max: 3000,
value: 1232,
options: {
colors: ["#3678c1", '#BED1E3'],
textColor: "#3678c1",
animationOptions: {frames: 60} // Doesn't need to be a string
}
}).draw();
async function getSessionInfo(){
let myPromise = new Promise(function(myResolve, myReject) {
session.defaultSession.cookies.get({name: "human_presence"}, (error,cookies)=>{
if(error){ myReject(error)}
if(cookies.length>0){
let arr = cookies[0];
if(arr.name === "human_presence" && ( (Date.now()-arr.expirationDate) < 600000)){
let obj = JSON.parse(arr.value);
myResolve(obj.accessToken);
}
else{ myResolve("Token bulunamadı")}
}
});
});
return await myPromise;
}
function httpCall(){
getSessionInfo().then(function (val){
let method = "GET";
let url = "http://localhost:4000/classroom/101";
let xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
let obj = JSON.parse(this.responseText);
console.log(obj);
document.getElementById("dateTime-101").innerHTML = "Son Kayıt Zamanı : "+obj.created;
document.getElementById("NoS-101").innerHTML = "Öğrenci Sayısı : "+obj.NoS;
temp.value = parseInt(obj.Temp);
hum.value = parseInt(obj.Hum);
iaq.value = parseInt(obj.IAQ);
RGraph.redrawCanvas(temp.canvas);
RGraph.redrawCanvas(hum.canvas);
RGraph.redrawCanvas(iaq.canvas);
}
});
xmlHttpRequest.open(method, url);
xmlHttpRequest.setRequestHeader('Authorization', 'Bearer ' + val);
xmlHttpRequest.send();
})
}
window.onload = httpCall();
window.setInterval(function(){
httpCall();
}, 20000);
Here's my answer that was posted to the RGraph forum:
This is as a result of the HorseShoe meter not really being a 'real' RGraph chart object - but an adaptation of the Pie chart. As a result I think it's easier to just redraw the entire chart when you update it.
Here's some code:
<canvas id="cvs" width="400" height="400">[No canvas support]</canvas>
<script>
function draw (value)
{
RGraph.reset(document.getElementById('cvs'));
new RGraph.HorseshoeMeter({
id: 'cvs',
min: 0,
max: 10000,
value: value,
options: {
}
}).roundRobin();
}
delay = 2000;
function update ()
{
var value = Math.random(0, 1000);
draw(value * 10000);
// Call ourselves again
setTimeout(update, delay);
}
setTimeout(update, delay);
</script>
And here's a CodePen of the code:
https://codepen.io/rgraph/pen/gOLYOej
Related
I have a project where I created the backend with flask. It reads the data from the csv file and transfers it to html. It reads data every second with Ajax. Then I visualize the data with plotly.js. With Ajax, every get operation comes with a delay.I am working with approximately 2000 data.
However, there is a delay in my code. How can I refactor this code? What can I do to avoid delay?
$(function requestData() {
$.ajax({
type: "GET",
url: "/deneme3",
success: function (data) {
//console.log('success',data);
//console.log('success',data[0]);
//console.log('success',data[1]);
var enlem = [];
var boylam = [];
var ch1 = [];
var ch2 = [];
var ch3 = [];
var ch4 = [];
enlem = data[0];
boylam = data[1];
ch1 = data[2];
ch2 = data[3];
ch3 = data[4];
ch4 = data[5];
//console.log('enlem',enlem);
//console.log('boylam',boylam);
var trace1 = {
x: enlem,
y: boylam,
mode: "markers",
marker: {
size: 10,
color: ch1,
colorbar: { x: -0.2, len: 1 },
colorscale: "Jet",
},
};
var data = [trace1];
var layout = {
title: "Scatter Plot with a Color Dimension",
};
Plotly.newPlot("tester", data, layout);
setInterval(function () {
var update = {
x: [[enlem]],
y: [[boylam]],
};
Plotly.extendTraces("tester", update, [0]);
}, 100);
//ch1 grafik
var trace2 = {
y: ch1,
type: "scatter",
};
var data2 = [trace2];
var layout2 = {
title: "CH1",
};
Plotly.newPlot("ch1", data2, layout2);
setInterval(function () {
var update = {
y: [[ch1]],
};
Plotly.extendTraces("ch1", update, [0]);
}, 100);
//ch2 grafik
var trace3 = {
y: ch2,
type: "scatter",
};
var data3 = [trace3];
var layout3 = {
title: "CH2",
};
Plotly.newPlot("ch2", data3, layout3);
setInterval(function () {
var update = {
y: [[ch2]],
};
Plotly.extendTraces("ch2", update, [0]);
}, 100);
//ch3 grafik
var trace4 = {
y: ch3,
type: "scatter",
};
var data4 = [trace4];
var layout4 = {
title: "CH3",
};
Plotly.newPlot("ch3", data4, layout4);
setInterval(function () {
var update = {
y: [[ch3]],
};
Plotly.extendTraces("ch3", update, [0]);
}, 100);
//ch4 grafik
var trace5 = {
y: ch4,
type: "scatter",
};
var data5 = [trace5];
var layout5 = {
title: "CH4",
};
Plotly.newPlot("ch4", data5, layout5);
setInterval(function () {
var update = {
y: [[ch4]],
};
Plotly.extendTraces("ch4", update, [0]);
}, 100);
},
});
setTimeout(requestData, 100);
});
Also, which of the Ajax and socketio would it make more sense to use?
As discussed in the comments, something like this might work: initialize empty plots, then just fill in data in the update function:
function plotData(data) {
const [enlem, boylam, ...chs] = data;
Plotly.extendTraces("tester", {
x: [[enlem]],
y: [[boylam]],
}, [0]);
for (let i = 0; i < 4; i++) {
const j = i + 1;
Plotly.extendTraces(`ch${j}`, {
y: [[chs[i]]],
}, [0]);
}
// After success, wait before loading more data
setTimeout(requestData, 1000);
}
function requestData() {
// Simulate a successful response that returns 6 numbers.
plotData([Math.random(), Math.random(), Math.random(), Math.random(), Math.random(), Math.random()]);
// If a real endpoint was available, you could do something like
/*$.ajax({
type: "GET",
url: "/deneme3",
success: plotData,
});*/
}
function initialize() {
Plotly.newPlot("tester", [{
x: [],
y: [],
mode: "markers",
marker: {
size: 10,
colorbar: { x: -0.2, len: 1 },
colorscale: "Jet",
},
}], {
title: "Scatter Plot with a Color Dimension",
});
for (let i = 1; i <= 4; i++) {
Plotly.newPlot(`ch${i}`, [{
y: [],
type: "scatter",
}], {
title: `CH${i}`,
});
}
requestData(); // Fire off first update
}
$(initialize);
div {
width: 33%;
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js" charset="utf-8"></script>
<div id="tester"></div>
<div id="ch1"></div>
<div id="ch2"></div>
<div id="ch3"></div>
<div id="ch4"></div>
I'm trying to show weight_id retrieved from mysql data in a chart.js tooltip (shown as (weight_ids[index]) in the image). And later, I intend to show a modal instead of a tooltip to let users update or delete that data. I presume I cannot achieve that without linking the linechart's point data with id stored in mysql. How can I incorporate this id data?
I would appreciate any help very much.
enter image description here
My code is as follows:
<canvas id="myChart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4/dist/Chart.min.js"></script>
{{-- グラフを描画--}}
<script>
//ラベル
const labels = #json($date_labels);
// id
const weight_ids = #json($weight_ids);
//体重ログ
const weight_logs = #json($weight_logs);
const aryMax = function(a, b) {
return Math.max(a, b);
};
const aryMin = function(a, b) {
return Math.min(a, b);
};
let min_label = Math.floor((weight_logs).reduce(aryMin) - 0.5);
let max_label = Math.ceil((weight_logs).reduce(aryMax) + 0.5);
console.log(weight_ids);
console.log(weight_logs);
console.log(min_label, max_label);
//グラフを描画
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data : {
labels: labels, // x軸ラベル
datasets: [
{
label: `Weight (weight_ids[index])`,
data: weight_logs,
tension: 0,
borderColor: "rgba(37,78,255,1)",
backgroundColor: "rgba(0,0,0,0)",
pointRadius: 3
}
]
},
options: {
title: {
display: false,
text: ''
},
legend: {
display: false,
},
scales: {
yAxes: [
{
ticks: {
min: min_label, // ラベル最小値
max: max_label, // ラベル最大値
},
scaleLabel: {
display: true,
fontSize: 16,
labelString: '体重 (kg)'
}
}
],
},
hover: {
mode: 'point'
},
onClick: function clickHandler(evt) {
var firstPoint = myChart.getElementAtEvent(evt)[0];
if (firstPoint) {
var label = myChart.data.labels[firstPoint._index];
var value = myChart.data.datasets[firstPoint._datasetIndex].data[firstPoint._index];
console.log(label);
console.log(value);
if (value) {
$('#weidhtModal').modal('show');
}
}
}
}
});
</script>
Thank you!
I found a way to retrieve weight_id using the following function.
onClick: function clickHandler(evt, activeElements) {
if (activeElements.length) {
var element = this.getElementAtEvent(evt);
var index = element[0]._index;
var _datasetIndex = element[0]._datasetIndex;
var weightId = weight_ids[index];
var weightLog = weight_logs[index];
console.log(index);
console.log(weightId);
console.log(this.data.labels[index]);
console.log(weightLog);
}
}
I'm writing an 10-band equalizer with HTML5 Audio API and JavaScript. From what I researched online, the 10 bands can be created as BiquadFilterNode and connected one after another for the final effect:
var AudioContext = new AudioContext();
var filter = context.createBiquadFilter(); // create the filter node
filter.type = 'peaking';
filter.gain.value = 0; // Default gain value
filter.Q.value = 1;
filter.frequency.value = 60; // and 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000 for the rest 9 bands
(A very similar set up can be seen here).
So far so good. But now I'm stuck at the so-called "preamp" that's always seen on a standard equalizer. For example, this is Winamp's:
This is VOX's:
This is VLC's:
etc. you get the idea. My question is: What exactly does this "preamp" do, and how would I program it into my application?
There is a 10 band Equalizer within the waveform project https://wavesurfer-js.org/example/equalizer/index.html
try on codepen
// Equalizer
wavesurfer.on('ready', function() {
var EQ = [
{
f: 32,
type: 'lowshelf'
},
{
f: 64,
type: 'peaking'
},
{
f: 125,
type: 'peaking'
},
{
f: 250,
type: 'peaking'
},
{
f: 500,
type: 'peaking'
},
{
f: 1000,
type: 'peaking'
},
{
f: 2000,
type: 'peaking'
},
{
f: 4000,
type: 'peaking'
},
{
f: 8000,
type: 'peaking'
},
{
f: 16000,
type: 'highshelf'
}
];
// Create filters
var filters = EQ.map(function(band) {
var filter = wavesurfer.backend.ac.createBiquadFilter();
filter.type = band.type;
filter.gain.value = 0;
filter.Q.value = 1;
filter.frequency.value = band.f;
return filter;
});
I did something very similar to this for my project https://webamp.org. The relvant code looks something like this:
const BANDS = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000];
let output = context.createGain();
const bands = {};
BANDS.forEach((band, i) => {
const filter = context.createBiquadFilter();
bands[band] = filter;
if (i === 0) {
// The first filter, includes all lower frequencies
filter.type = "lowshelf";
} else if (i === band.length - 1) {
// The last filter, includes all higher frequencies
filter.type = "highshelf";
} else {
filter.type = "peaking";
}
filter.frequency.value = band;
filter.gain.value = 0;
output.connect(filter);
output = filter;
});
output.connect(context.destination);
You can find the full source code here: https://github.com/captbaritone/webamp/blob/master/js/media/index.js
Here is my code so far. I can see the selection rectangle, but zooming isn't happening.
what have I did wrong?
function Plot(container, data) {
this.options = {
lines: {
show: true
},
points: {
show: true
},
xaxis: {
tickDecimals: 0,
tickSize: 1
},
selection: { mode: "xy" }
}
console.log("script is running")
this.data = []
this.container = container;
this.plot = $.plot(container, this.data, this.options);
this.url = '/sensor/oscillogram_debug_data/'+110;
this.container.bind("plotselected", this.zoom);
this.zoom = function(event, reanges) {
if (ranges.xaxis.to - ranges.xaxis.from < 0.00001)
ranges.xaxis.to = ranges.xaxis.from + 0.00001;
if (ranges.yaxis.to - ranges.yaxis.from < 0.00001)
ranges.yaxis.to = ranges.yaxis.from + 0.00001;
this.plot = $.plot(this.container, this.plot.getData(),
$.extend(true, {}, this.options, {
xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
}));
}
}
var plot = new Plot($("#output_plot_container"));
var updateChart = function() {
$.getJSON(plot.url, function(newdata) {
for (var f_id in newdata)
if (newdata.hasOwnProperty(f_id)) {
if (f_id='demodulated') {
// plot.plot.setData([newdata[f_id]])
// plot.plot.setupGrid()
// plot.plot.draw()
}
}
})
}
A few problems here:
1.) You are binding to this.zoom before it exists, reverse those calls (and note typo in "reanges"):
this.zoom = function(event, ranges) {
....
this.container.bind("plotselected", this.zoom);
2.) Your attempt at some sort of OO scoping within this.zoom just isn't going to work. Once that function is bound, it doesn't have access to it's parent scope. If you want the this to be available in the bind, you can pass it in as eventData:
this.container.bind("plotselected", {obj: this}, this.zoom); // and replace the this in this.zoom with obj
Here's a working fiddle.
I'm struggling to solve a problem I have with getting a chart to be redrawn after navigating to another view and then return back to the same chart view.
I'm using Backbone.js and Underscore as a MVC and templating solution for my application.
When I navigate to the charting page initially it works great, but if I move away and then come back I get a `TypeError: chart.series[0] is undefined in the console log.
I have highlighted line where the error occurs in the code below, close to the end.
My thought is that I may need to destroy() the chart at some point, but I'm unsure where I would do this and if it would solve my problem.
I recently changed the script to now use HighStock 'Highstock JS v1.3.6 (2013-10-04)' from earlier HighCharts ver 2.3.5, where it appeared that I did not have this issue.
The app is live online if anyone really needs or wants to see it in action, let me know.
The following code section is the function thatis called by the Backbone router.
If there is a need for other sections of code, please let me know.
I'll be grateful for any advice.
EDIT:
I have managed to get this in JSFiddle for anyone to view the problem.
Clickty clack your fury tailless one here http://jsfiddle.net/rockwallaby/pqKWj
When you first run it up, you will get a trend being displayed.
Then hit the 'Go to a different page' link, you will get a fairly blank page.
On that page there is a link to bring you back to the trend page.
Hitting that link brings you back but the trend does not get rendered correctly due to the above mentioned error.
//=================================================================================
// trendsBattery
// A simple trend view showing Battery Volts and Solar Charge
//
window.trendsBattery = Backbone.View.extend({
trendModel: new TrendsModel(),
template: _.template(trendsTemplate),
chart: null,
chartoptions:{
chart: {
renderTo: 'chart-container',
},
rangeSelector: {
enabled: false,
},
title:{
text:'Battery Volts & Solar Amps'
},
xAxis: {
type:'datetime',
dateTimeLabelFormats: {month:'%e. %b',year:'%b'}
},
yAxis: [{
title :{text: 'Battery Volts'},
min: 22,
max: 32,
minorGridLineColor: '#E0E0E0',
},
{
title :{text: 'Solar Charge Amps'},
min: 0,
max: 16,
opposite: true,
},
],
series:[
{yAxis: 0, data: [], type: 'line', step: true, name: 'Battery Vdc'},
{yAxis: 1, data: [], type: 'line', step: true, name: 'Solar Amps'},
],
},
render:function() {
that = this;
$(this.el).html(this.template());
this.chartoptions.chart.width = (windowWidth);
this.chartoptions.chart.height = (windowHeight - 150);
setTimeout(function() {
chart = new Highcharts.StockChart(that.chartoptions);
chart.events ={load: that.requestData(this.chart) };
},20);
return this;
},
requestData: function(chart){
var querystring = '//myHostServer.com/myFolder/myPHP.php';
jQuery.get(querystring, null, function(csv, state, xhr) {
if (typeof csv !== 'string') {
csv = xhr.responseText;
};
csv = csv.split(/\n/g);
var vB_array = [];
var iS_array = [];
jQuery.each(csv, function (i, line) {
if (line.length > 1) {
line_array = line.split(',');
var date = parseInt(line_array[0]) * 1000;
var vBpoint = {};
var iSpoint = {};
vBpoint.x = date;
iSpoint.x = date;
vBpoint.y = parseFloat(line_array[1]);
iSpoint.y = parseFloat(line_array[4]);
vB_array.unshift(vBpoint);
iS_array.unshift(iSpoint);
};
});
chart.series[0].setData(vB_array, false); // <<<<< Problem Area
chart.series[1].setData(iS_array, false);
chart.redraw();
});
chart.xAxis[0].setExtremes(); // expand out the scrollbar when moving through time:
},
});
I just updated jsfiddle with the suggestion I provided in comment, it's working.
window.trendView = Backbone.View.extend({
trendModel: new TrendsModel(),
template: _.template(trendTemplate),
chart: null,
getChartOptions: function () {
return {
chart: {
animation: true,
renderTo: 'chart-container',
backgroundColor: '#fff'
},
rangeSelector: {
enabled: false
},
title: {
text: 'Battery Volts & Solar Amps'
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
month: '%e. %b',
year: '%b'
} // don't display the dummy year:
},
yAxis: [{
title: {
text: 'Battery Volts'
},
min: 22,
max: 32,
minorGridLineColor: '#E0E0E0'
}, {
title: {
text: 'Solar Charge Amps'
},
min: 0,
max: 16,
opposite: true
}],
series: [{
yAxis: 0,
data: [],
type: 'line',
step: true,
name: 'Battery Vdc'
}, {
yAxis: 1,
data: [],
type: 'line',
step: true,
name: 'Solar Amps'
}]
}
},
render: function () {
that = this;
$(this.el).html(this.template());
var chartOptions = that.getChartOptions();
chartOptions.chart.width = (windowWidth - 50);
chartOptions.chart.height = (windowHeight - 50);
setTimeout(function () {
chart = new Highcharts.StockChart(chartOptions);
chart.events = {
load: that.requestData(this.chart)
};
}, 20);
return this;
},
requestData: function (chart) {
var querystring = '//paulalting.com/hydrosolar/clientGET.php?id=trendVolts&start=6400&size=200';
console.log(querystring);
jQuery.get(querystring, null, function (csv, state, xhr) {
if (typeof csv !== 'string') {
csv = xhr.responseText;
}
csv = csv.split(/\n/g);
var vB_array = [];
var iS_array = [];
jQuery.each(csv, function (i, line) {
if (line.length > 1) {
line_array = line.split(',');
var date = parseInt(line_array[0], 10) * 1000;
var vBpoint = {};
var iSpoint = {};
vBpoint.x = date;
iSpoint.x = date;
vBpoint.y = parseFloat(line_array[1]);
iSpoint.y = parseFloat(line_array[4]);
vB_array.unshift(vBpoint);
iS_array.unshift(iSpoint);
}
});
chart.series[0].setData(vB_array, false); // <<<<< Problem Area
chart.series[1].setData(iS_array, false);
chart.redraw();
});
chart.xAxis[0].setExtremes(); // expand out the scrollbar when moving through time:
}
});
here is the link
http://jsfiddle.net/pqKWj/14/
If you are interested let me know I see some more similar problems in the code, which I think fine for now, but will create issues, when you have 2 charts in the same page etc. we can talk