ASP.NET Populate Apex Chart using a String Array from Controller - javascript

I am trying to populate the chart data from within my controller. I think im on the right path by using a string array but ive also tried an int array and had the same result.
Currently the page shows this,
Picture of the chart live
And this is my output on the Dev Tools,
Picture of Dev Tools Console
Here is how I'm currently grabbing the data from my Model,
<script type="text/javascript">
$(document).ready(function () {
var error = #((TempData["errorMessage"] != null).ToString().ToLower());
if (error == true) {
console.log("hello world");
$('#errorModal').modal('show');
}
var EmbroideryTally = #Html.Raw(Json.Serialize(Model.EmbroideryTally));
console.log(EmbroideryTally);
var options = {
chart: {
height: 550,
type: "line",
stacked: false
},
colors: ["#E5AE10", "#6D77E0", "#15BE90", "#E15C79", "#68727A"],
series: [
{
name: "Embroidery",
data: []
}
//,
//{
// name: "Engraving",
// data: [108, 128, 98, 83, 193, 26, 55, 66, 79, 29, 37, 66, 154, 64, 104, 172, 34, 29, 37, 66, 44, 150, 50, 200]
//},
//{
// name: "Metal",
// data: [167, 108, 27, 177, 198, 12, 141, 172, 118, 175, 165, 52, 19, 157, 33, 42, 121, 176, 43, 14, 158, 80, 82, 125]
//},
//{
// name: "Uvp",
// data: [0, 54, 2, 13, 199, 46, 165, 183, 167, 7, 152, 185, 17, 27, 169, 25, 9]
//},
//{
// name: "Unknown",
// data: [93, 170, 52, 16, 126, 176, 82, 40, 132, 4, 62, 43, 35, 34, 195, 75, 122]
//}
],
stroke: {
width: [8, 8, 8, 8, 8]
},
plotOptions: {
bar: {
columnWidth: "20%"
}
},
xaxis: {
categories: [01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
},
labels: ['Embroidery', 'Engraving', 'Metal', 'UV', 'Unknown'],
noData: { text: 'Waiting for scans...', style: { color: '#ffffff' }}
};
var barCodeChart = new ApexCharts(document.querySelector("#barCodeChart"), options);
barCodeChart.render();
barCodeChart.updateSeries([{
name: "Embroidery",
data: [#Html.Raw(Json.Serialize(Model.EmbroideryTally))]
}]);
});
</script>
Here is my Model
namespace MyApp.Models
{
public class BarcodeViewModel
{
public BarcodeViewModel()
{
BarcodeScan = new BarcodeScan();
EmbroideryTally = new String[24];
}
public string[] EmbroideryTally { get; set; }
}
}
And heres my Controller (I've taken a good chunk of stuff out as its not important)
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind("BarcodeScanCode")] BarcodeScan barcode)
{
try
{
_barcodeViewModel.EmbroideryTally[0] = "21";
_barcodeViewModel.EmbroideryTally[1] = "14";
_barcodeViewModel.EmbroideryTally[2] = "64";
_barcodeViewModel.EmbroideryTally[3] = "150";
_barcodeViewModel.EmbroideryTally[4] = "32";
catch (Exception e)
{
Console.WriteLine("An issue has arisen:" + e.Message);
TempData["errorMessage"] = "An ERROR has occurred. Barcode not properly submitted. Barcode: " + barcode.BarcodeScanCode;
}
finally
{
await conn.CloseAsync();
}
return View("Index", _barcodeViewModel);
}

Related

ApexChart column resize on zoom

I would like to resize the columns width when the user zoom on my chart. Could you suggest any method or option? I searched through the documentation but I didn't find any solution. Until now I tried by changing the bar width percentage, the responsive option and the stroke width. The stroke has the side effect of overlapping the bars but I need them separate
Before Zoom
After Zoom actual behaviour
After Zoom desired behaviour
Code used until now
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Bar with Custom DataLabels</title>
<link href="../../assets/styles.css" rel="stylesheet" />
<style>
#chart {
max-width: 650px;
margin: 35px auto;
}
</style>
<script>
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/promise-polyfill#8/dist/polyfill.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/eligrey-classlist-js-polyfill#1.2.20171210/classList.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/findindex_polyfill_mdn"><\/script>'
);
</script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
// Replace Math.random() with a pseudo-random number generator to get reproducible results in e2e tests
// Based on https://gist.github.com/blixt/f17b47c62508be59987b
var _seed = 42;
Math.random = function () {
_seed = (_seed * 16807) % 2147483647;
return (_seed - 1) / 2147483646;
};
</script>
</head>
<body>
<div id="chart"></div>
<script>
var options = {
series: [
{
name: 'Net Profit',
data: [
95, 4, 48, 95, 71, 16, 44, 98, 75, 94, 28, 61, 76, 1, 54, 90, 19,
5, 37, 57, 88, 31, 41, 59, 27, 96, 20, 65, 84, 49, 67, 73, 78, 22,
75, 82, 67, 16, 4, 95, 84, 100, 76, 88, 66, 65, 14, 15, 46, 23,
48, 91, 23, 18, 32, 15, 71, 73, 28, 2, 61, 21, 63, 30, 35, 62, 29,
11, 71, 95, 43, 9, 59, 20, 85, 46, 59, 82, 4, 54, 60, 11, 15, 51,
34, 12, 19, 45, 2, 89, 3, 6, 60, 17, 57, 16, 90, 13, 46, 8,
],
},
{
name: 'Revenue',
data: [
97, 46, 49, 16, 11, 41, 36, 38, 16, 89, 71, 42, 68, 79, 52, 64,
40, 38, 29, 32, 50, 74, 88, 76, 65, 50, 66, 56, 42, 45, 46, 39,
29, 57, 68, 75, 34, 5, 100, 47, 79, 76, 53, 78, 39, 46, 13, 80,
22, 61, 67, 61, 17, 86, 65, 76, 82, 63, 27, 58, 64, 6, 100, 39,
25, 39, 14, 79, 12, 44, 9, 72, 63, 96, 27, 77, 70, 36, 100, 96, 5,
36, 89, 25, 67, 53, 61, 86, 64, 46, 52, 41, 56, 1, 93, 45, 49, 23,
35, 11,
],
},
{
name: 'Free Cash Flow',
data: [
20, 32, 92, 20, 36, 25, 4, 61, 77, 49, 11, 74, 15, 21, 49, 52, 11,
12, 12, 21, 78, 47, 95, 6, 68, 51, 66, 29, 67, 22, 100, 66, 42,
48, 8, 94, 87, 74, 43, 72, 90, 34, 66, 23, 82, 79, 64, 79, 89, 53,
25, 70, 25, 48, 43, 11, 17, 63, 30, 100, 79, 29, 41, 3, 99, 78,
93, 53, 12, 99, 30, 76, 30, 18, 5, 11, 16, 38, 49, 87, 21, 67, 41,
28, 13, 82, 1, 88, 79, 53, 3, 63, 61, 4, 5, 75, 83, 62, 17, 43,
],
},
],
annotations: {
points: [
{
x: 'Bananas',
seriesIndex: 0,
label: {
borderColor: '#775DD0',
offsetY: 0,
style: {
color: '#fff',
background: '#775DD0',
},
text: 'Bananas are good',
},
},
],
},
chart: {
height: 350,
type: 'bar',
},
plotOptions: {
bar: {
columnWidth: '100%',
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 2,
},
grid: {
row: {
colors: ['#fff', '#f2f2f2'],
},
},
xaxis: {
labels: {
rotate: -45,
},
categories: [
31, 48, 33, 88, 5, 91, 76,
],
tickPlacement: 'on',
},
yaxis: {
title: {
text: 'Servings',
},
},
fill: {
type: 'gradient',
gradient: {
shade: 'light',
type: 'horizontal',
shadeIntensity: 0.25,
gradientToColors: undefined,
inverseColors: true,
opacityFrom: 0.85,
opacityTo: 0.85,
stops: [50, 0, 100],
},
}
};
var chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
</script>
</body>
this is not a complete answer but wanted to share my findings.
IMO the functionality the OP requests should be the default behavior.
regardless, I found that by using the zoomed event, we can find the x-axis range of the zoom.
then remove the data points from the series that are outside of that range and re-draw the chart.
which results in exactly the desired behavior.
however, this kills the ability to zoom out to original series.
to make this work, I think you would need to implement custom zoom buttons,
to allow keeping track of which action occurred, zoom in or out.
this would allow you to know which data points to include when the chart is re-drawn.
you can use the zoomX method to manually set the zoom level.
see following working snippet for zoom-in only functionality.
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Bar with Custom DataLabels</title>
<link href="../../assets/styles.css" rel="stylesheet" />
<style>
#chart {
max-width: 650px;
margin: 35px auto;
}
</style>
<script>
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/promise-polyfill#8/dist/polyfill.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/eligrey-classlist-js-polyfill#1.2.20171210/classList.min.js"><\/script>'
);
window.Promise ||
document.write(
'<script src="https://cdn.jsdelivr.net/npm/findindex_polyfill_mdn"><\/script>'
);
</script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script>
// Replace Math.random() with a pseudo-random number generator to get reproducible results in e2e tests
// Based on https://gist.github.com/blixt/f17b47c62508be59987b
var _seed = 42;
Math.random = function () {
_seed = (_seed * 16807) % 2147483647;
return (_seed - 1) / 2147483646;
};
</script>
</head>
<body>
<div id="chart"></div>
<script>
var data = [
{
name: 'Net Profit',
data: [
95, 4, 48, 95, 71, 16, 44, 98, 75, 94, 28, 61, 76, 1, 54, 90, 19,
5, 37, 57, 88, 31, 41, 59, 27, 96, 20, 65, 84, 49, 67, 73, 78, 22,
75, 82, 67, 16, 4, 95, 84, 100, 76, 88, 66, 65, 14, 15, 46, 23,
48, 91, 23, 18, 32, 15, 71, 73, 28, 2, 61, 21, 63, 30, 35, 62, 29,
11, 71, 95, 43, 9, 59, 20, 85, 46, 59, 82, 4, 54, 60, 11, 15, 51,
34, 12, 19, 45, 2, 89, 3, 6, 60, 17, 57, 16, 90, 13, 46, 8,
],
},
{
name: 'Revenue',
data: [
97, 46, 49, 16, 11, 41, 36, 38, 16, 89, 71, 42, 68, 79, 52, 64,
40, 38, 29, 32, 50, 74, 88, 76, 65, 50, 66, 56, 42, 45, 46, 39,
29, 57, 68, 75, 34, 5, 100, 47, 79, 76, 53, 78, 39, 46, 13, 80,
22, 61, 67, 61, 17, 86, 65, 76, 82, 63, 27, 58, 64, 6, 100, 39,
25, 39, 14, 79, 12, 44, 9, 72, 63, 96, 27, 77, 70, 36, 100, 96, 5,
36, 89, 25, 67, 53, 61, 86, 64, 46, 52, 41, 56, 1, 93, 45, 49, 23,
35, 11,
],
},
{
name: 'Free Cash Flow',
data: [
20, 32, 92, 20, 36, 25, 4, 61, 77, 49, 11, 74, 15, 21, 49, 52, 11,
12, 12, 21, 78, 47, 95, 6, 68, 51, 66, 29, 67, 22, 100, 66, 42,
48, 8, 94, 87, 74, 43, 72, 90, 34, 66, 23, 82, 79, 64, 79, 89, 53,
25, 70, 25, 48, 43, 11, 17, 63, 30, 100, 79, 29, 41, 3, 99, 78,
93, 53, 12, 99, 30, 76, 30, 18, 5, 11, 16, 38, 49, 87, 21, 67, 41,
28, 13, 82, 1, 88, 79, 53, 3, 63, 61, 4, 5, 75, 83, 62, 17, 43,
],
},
];
var options = {
series: data,
annotations: {
points: [
{
x: 'Bananas',
seriesIndex: 0,
label: {
borderColor: '#775DD0',
offsetY: 0,
style: {
color: '#fff',
background: '#775DD0',
},
text: 'Bananas are good',
},
},
],
},
chart: {
height: 350,
id: 'thisChart',
type: 'bar',
events: {
zoomed: function(chartContext, {xaxis, yaxis}) {
console.log('zoom', xaxis);
var newSeries = data.map(function (series) {
var newData = [];
series.data.forEach(function (row, index) {
if ((index >= xaxis.min) && (index <= xaxis.max)) {
newData.push(row);
}
});
return {
name: series.name,
data: newData
};
});
ApexCharts.exec('thisChart', 'updateSeries', newSeries, true);
}
}
},
plotOptions: {
bar: {
columnWidth: '100%',
},
},
dataLabels: {
enabled: false,
},
stroke: {
width: 2,
},
grid: {
row: {
colors: ['#fff', '#f2f2f2'],
},
},
xaxis: {
labels: {
rotate: -45,
},
categories: [
31, 48, 33, 88, 5, 91, 76,
],
tickPlacement: 'on',
},
yaxis: {
title: {
text: 'Servings',
},
},
fill: {
type: 'gradient',
gradient: {
shade: 'light',
type: 'horizontal',
shadeIntensity: 0.25,
gradientToColors: undefined,
inverseColors: true,
opacityFrom: 0.85,
opacityTo: 0.85,
stops: [50, 0, 100],
},
}
};
var chart = new ApexCharts(document.querySelector('#chart'), options);
chart.render();
</script>
</body>

Group data by weekdays in Highchart

I'm plotting a graph that needs to combine data of a selected date range to weekdays i mean if i selected a date range from ex: 2021-05-01 to 2021-05-31 in that consider 2021-05-01,2021-05-08,2021-05-15 these days are Friday so i need to combine datas of these dates and show as one data with label friday. With the current options that i used the chart is plotting like this. Is there any ways to display it correctly.
Demo Fiddle
This is the way that i currently getting the result
This is the result that i'm expecting
These are the current configd that i'm using in the highchart.
Highcharts.chart("multistackedbarchart-II", {
chart: {
type: "column",
},
title: {
text: "Sent/Received Comparison",
},
xAxis: {
title: {
text: "Day",
},
categories: [labels],
},
yAxis: {
min: 0,
title: {
text: "",
},
stackLabels: {
enabled: false,
style: {
fontWeight: "bold",
color:
// theme
(Highcharts.defaultOptions.title.style && Highcharts.defaultOptions.title.style.color) ||
"gray",
},
},
},
legend: {
align: "center",
verticalAlign: "bottom",
x: 0,
y: 0,
},
tooltip: {
headerFormat: "<b>{point.x}</b><br/>",
pointFormat: "{series.name}: {point.y}",
},
plotOptions: {
column: {
stacking: "normal",
dataGrouping: {
forced: true,
units: [['day', [1]]]
}
},
},
series: chartdata.multistackedbarchart,
credits: {
enabled: false,
},
});
Highcharts.setOptions({ lang: { noData: "No Data Available" } });
You can make a special function to do this sorting by using Array.map() and Array.filter() methods:
const categories = [
"2021-08-04",
"2021-08-05",
"2021-08-06",
"2021-08-07",
"2021-08-08",
"2021-08-09",
"2021-08-10",
"2021-08-11",
"2021-08-12",
"2021-08-13",
"2021-08-14",
"2021-08-15",
"2021-08-16",
"2021-08-17",
"2021-08-18",
"2021-08-19",
"2021-08-20",
"2021-08-21",
"2021-08-22",
"2021-08-23",
"2021-08-24",
"2021-08-25",
"2021-08-26",
"2021-08-27",
"2021-08-28",
"2021-08-29",
"2021-08-30",
"2021-08-31",
"2021-09-01",
"2021-09-02",
"2021-09-03",
"2021-09-04",
"2021-09-05",
"2021-09-06",
"2021-09-07",
"2021-09-08",
"2021-09-09",
"2021-09-10",
"2021-09-11",
"2021-09-12",
"2021-09-13",
"2021-09-14",
"2021-09-15",
"2021-09-16",
"2021-09-17",
"2021-09-18",
"2021-09-19",
"2021-09-20",
"2021-09-21",
"2021-09-22",
"2021-09-23",
"2021-09-24",
"2021-09-25",
"2021-09-26",
"2021-09-27",
"2021-09-28",
"2021-09-29",
"2021-09-30",
"2021-10-01",
"2021-10-02",
"2021-10-03",
"2021-10-04",
"2021-10-05",
"2021-10-06",
"2021-10-07",
"2021-10-08",
"2021-10-09",
"2021-10-10",
"2021-10-11",
"2021-10-12"]
const messagesSent = [ 32,
60,
71,
3,
1,
25,
16,
23,
28,
25,
2,
1,
43,
49,
32,
35,
26,
2,
1,
8,
36,
47,
15,
20,
2,
1,
2,
18,
20,
30,
43,
4,
4,
15,
14,
48,
39,
3,
2,
0,
48,
34,
15,
9,
1,
3,
1,
85,
27,
72,
11,
4,
2,
0,
29,
13,
21,
15,
32,
2,
0,
58,
37,
37,
24,
5,
1,
0,
0,
0]
const messagesReceived = [29,
79,
80,
7,
2,
24,
32,
23,
44,
42,
3,
1,
65,
69,
46,
47,
23,
3,
1,
28,
35,
65,
22,
19,
4,
1,
7,
10,
32,
31,
13,
8,
2,
4,
48,
53,
46,
7,
4,
0,
48,
40,
23,
18,
2,
6,
2,
79,
25,
86,
9,
8,
5,
0,
25,
18,
18,
14,
37,
2,
0,
52,
70,
27,
25,
17,
1,
0,
0,
0]
const organizeData = (days, sent, received) => {
const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
// get name of weekday
const getDayOfWeek = date => {
const dayOfWeek = new Date(date).getDay();
return isNaN(dayOfWeek) ? null : dayNames[dayOfWeek];
}
return dayNames.map((dayName) => {
let correspondingMessagesSent = []
let correspondingMessagesReceived = []
const matchedDays = days.filter((day, index) => {
if(dayName === getDayOfWeek(day)) {
correspondingMessagesSent.push(sent[index])
correspondingMessagesReceived.push(received[index])
return day
}
})
return { [dayName]: { dates: matchedDays,
sent: correspondingMessagesSent,
received: correspondingMessagesReceived} }
})
}
console.log(organizeData(categories, messagesSent, messagesReceived))
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

Limit x-axis in Apexcharts.js

I want to limit the x-axis in the bar graph I'm using, I have multiple values but I want to show only 7 and then the user can scroll to see the remaining. Does this option exist?
Setting the value of the xaxis.range property should help.
var options = {
series: [
{
name: 'PRODUCT A',
data: [44, 55, 41, 67, 22, 43, 13, 23, 20, 8, 13, 27]
}, {
name: 'PRODUCT B',
data: [13, 23, 20, 8, 13, 27, 11, 17, 15, 15, 21, 14]
}, {
name: 'PRODUCT C',
data: [11, 17, 15, 15, 21, 14, 44, 55, 41, 67, 22, 43]
}
],
chart: {
type: 'bar',
height: 350,
stacked: true,
toolbar: {
show: true
}
},
xaxis: {
range: 7
}
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();

Reassign variables in if/else (Javascript)

How can I achieve a reassigned list (or any other value for that matter) in javascript?
I've tried to do as I'd do in python, and make a empty list and assign it if my conditions are met, but it seems that javascript will fall right back on what's assigned out of my if/else
My goal is to achieve something like this:
let data1 = [];
let data2 = [];
let data3 = [];
document.addEventListener("DOMContentLoaded", function(){
if (document.getElementById('minus').checked) {
let data1 = [-64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
let data2 = [-23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
let data3 = [-64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
} else {
let data1 = [64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
let data2 = [23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
let data3 = [64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
}
});
//Further code that uses the variables we just set
fiddle on my issue:
https://jsfiddle.net/vk8swjc3/
You're currently redefining all of those data variables by saying let again. Remove the lets and do data1 = [-64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34] directly to reassign them.
Two problems:
If you use let x inside a block, you're creating a new variable x in the inner scope. Remove let and you're reassigning the original x.
If you reassign them inside a DOMContentLoaded callback, the new values won't be available to the immediately running code after you set up that callback (only in the callback itself, or once the callback has run). See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
Here's a demo of the order of execution:
console.log('top')
document.addEventListener("DOMContentLoaded", () => {
console.log('DOMContentLoaded')
executeWithinCallback()
})
const executeWithinCallback = () => {
console.log('after DOMContentLoaded')
}
console.log('bottom')
When you are use var, let or const on a scope(curly braces) you are defined a variable that you can use only inside of that scope.
So if you want to use top level variable in another scope then you shouldn't use var, let or const to assign a value to variable.
You can look here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Having addressed the variable scoping issues that you had in your initial post we can now look at the larger part of your question which seems to be the matter of changing data, or at least setting initial data based on the state of a control.
Your fiddle is working as intended, but not as you expect it to. If you console.log() any of the data arrays after the conditional within the DOMContentLoaded you will see the updated array.
let data1 = [];
let data2 = [];
let data3 = [];
document.addEventListener("DOMContentLoaded", function(){
if (document.getElementById('minus').checked) {
data1 = [-64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
data2 = [-23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
data3 = [-64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
} else {
data1 = [64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
data2 = [23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
data3 = [64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
}
console.log(data1);
});
// [64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34]
However, by the time that runs you have already set up your chart with the empty array values and it has rendered. Changing the values of the data arrays after that will have no effect on the rendered chart, nor on the values of the arrays assigned to chartData.datasets[n].data
In order to update the chart you need to change these dataset values and call update on the the chart.
let barVertical = document.getElementById("barVertical");
let barVerticalChart = new Chart(barVertical, {
type: "bar",
data: chartData,
options: chartOptions,
});
const minus = document.getElementById('minus');
minus.addEventListener('change', (e) => {
if (e.target.checked) {
chartData.datasets[0].data = [-64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
chartData.datasets[1].data = [-23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
chartData.datasets[2].data = [-64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
} else {
chartData.datasets[0].data = [64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
chartData.datasets[1].data = [23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
chartData.datasets[2].data = [64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
}
barVerticalChart.update();
});
Updated fiddle: https://jsfiddle.net/q3tmon21/
Or, to simply make your code run as you seem to expect, using the conditionally set arrays on the first render, simply move all the code that comes after it into the DOMContentLoaded listener.
let data1 = [];
let data2 = [];
let data3 = [];
document.addEventListener("DOMContentLoaded", function(){
if (document.getElementById('minus').checked) {
data1 = [-64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
data2 = [-23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
data3 = [-64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
} else {
data1 = [64, 31, 23, 34, 23, 30, 50, 43, 29, 64, 22, 34];
data2 = [23, 45, 83, 74, 99, 83, 64, 72, 50, 44, 36, 45];
data3 = [64, 75, 43, 24, 63, 72, 88, 24, 84, 93, 45, 60];
}
let labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
let chartData = {
labels: labels,
datasets: [
{
label: "Data1",
data: data1,
backgroundColor: "rgba(154, 18, 179, .7)",
},
{
label: "Data2",
data: data2,
backgroundColor: "rgba(232, 126, 4, .7)",
},
{
label: "Data3",
data: data3,
backgroundColor: "rgba(0, 230, 64, .7)",
},
],
};
let barVertical = document.getElementById("barVertical");
let barVerticalChart = new Chart(barVertical, {
type: "bar",
data: chartData,
options: chartOptions,
});
});

Protobuf over zeromq/zwssock to JSMQ/ProtoBuf.js messages are not fully recieved

I'm sending Protobuf encoded data over zwssock (czmq) -- which is an websocket extension for zcmq -- to JSMQ.js after which the decoding of the protobuf data takes place.
OS: Windows
Browser: Chrome 40.0.2
ØMQ: 4.0.4
czmq: 2.2.0.
With the following problem:
the data recieved does not contain all bytes that have been send.
In fact after inspection it turns out that all bytes where recieved up to the first 0 byte.
Real example:
data send:
10,4,78,77,69,65,-110,3,19,8,101,-86,6,14,8,1,16,-40,-126,-27,-14,-12,-87,-61,2,
-16,1,1,-110,3,93,8,100,80,0,-94,6,86,34,73,36,71,80,82,77,67,44,49,48,51,50,51,
49,46,54,48,49,44,86,44,53,50,48,53,46,54,52,50,54,55,48,44,78,44,48,48,54,49,57
,46,54,49,51,57,52,55,44,69,44,52,51,46,50,44,51,54,46,52,44,50,51,48,49,49,53,4
4,44,44,83,42,54,68,32,74,9,69,80,83,71,58,52,51,50,54,-30,3,97,10,4,78,77,69,65
,18,73,36,71,80,82,77,67,44,49,48,51,50,51,49,46,54,48,49,44,86,44,53,50,48,53,4
6,54,52,50,54,55,48,44,78,44,48,48,54,49,57,46,54,49,51,57,52,55,44,69,44,52,51,
46,50,44,51,54,46,52,44,50,51,48,49,49,53,44,44,44,83,42,54,68,32,82,14,10,5,8,2
,-80,1,2,-94,6,4,8,8,16,6
data recieved:
0, 10, 4, 78, 77, 69, 65, 146, 3, 19, 8, 101, 170, 6, 14, 8, 1, 16,
137, 255, 156, 213, 244, 169, 195, 2, 240, 1, 1, 146, 3, 93, 8, 100,
80]
As you can see the byte after 80 is missing, and the squence now start with a 0 byte. I've tested with manually created data -- char* --, and everytime the same problem would occur.
The two functions below are directly taken from JSQM.js and are called by the websocket upon data recieved.
function onmessage(ev) {
if (ev.data instanceof Blob) {
var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function () {
processFrame(this.result);
};
fileReader.readAsArrayBuffer(ev.data);
} else if (ev.data instanceof ArrayBuffer) {
processFrame(ev.data);
}
// Other message type are not supported and will just be dropped
};
function processFrame(frame) {
var view = new Uint8Array(frame);
var more = view[0];
if (incomingMessage == null) {
incomingMessage = new JSMQ.Message();
}
incomingMessage.addBuffer(frame);
// last message
if (more == 0) {
if (that.onMessage != null) {
that.onMessage(that, incomingMessage);
}
incomingMessage = null;
}
}
In the onmessage/processFrame the received data already does not contain the full bytes sequence. As you can see the received byte sequence starts with a 0, matching the [more == 0] guard.
I was not able to get wireshark to sniff the packages send, checking
if the bytes where not correctly send.
One solution would be to use bytestuffing thus removing all 0 bytes.
But surely I've must have made a mistake somewhere?
As requested:
Internally we use the c++ library of zeromq, however since the websockets
are currently een extention on the c version we need to convert to c style message. As mentioned the data has been stuffed.
void CZeroMQConnection::Send(zmq::message_t& message)
{
zmsg_t* msg = zmsg_new();
std::vector<unsigned char> rpl;
std::copy_n(reinterpret_cast<char*>(message.data()), message.size(),std::back_inserter(rpl));
// Temporary stuffing on Websockets
char stuffChar = 1;
char invalidChar = 0;
std::vector<unsigned char> stuffed;
for (auto it = rpl.begin(); it != rpl.end(); ++it)
{
if (*it == invalidChar || *it == stuffChar)
{
stuffed.push_back(stuffChar);
stuffed.push_back((*it) + 1);
}
else
stuffed.push_back(*it);
}
// As mentioned added extra 0 byte, preventing superfluos data
stuffed.push_back(0);
zmsg_push(msg, _id);
zmsg_addstr(msg, reinterpret_cast<char*> (&stuffed[0]));
zwssock_send(_socket, &msg);
}
There is is not yet a bi-directional dataflow, this will come in the near future.
Thank you somdoron,
your post uses:
zmsg_addmem(msg, buf, 226);
while i was using:
zmsg_addstr(msg, reinterpret_cast<char*> (&stuffed[0]));
which will probably interpret the input as a C string.
This solved the problem, thanx a lot!
I try to reproduce the issue with chrome (40.0.2) without success, I got the entire message including the zeros.
c code:
static char *listen_on = "tcp://127.0.0.1:86";
int main(int argc, char **argv)
{
zctx_t *ctx;
zwssock_t *sock;
char *l = argc > 1 ? argv[1] : listen_on;
ctx = zctx_new();
sock = zwssock_new_router(ctx);
zwssock_bind(sock, l);
zmsg_t* msg;
zframe_t *id;
while (!zctx_interrupted)
{
msg = zwssock_recv(sock);
if (!msg)
break;
// first message is the routing id
id = zmsg_pop(msg);
while (zmsg_size(msg) != 0)
{
char * str = zmsg_popstr(msg);
printf("%s\n", str);
free(str);
}
zmsg_destroy(&msg);
msg = zmsg_new();
zmsg_push(msg, id);
char buf[226] = { 10, 4, 78, 77, 69, 65, -110, 3, 19, 8, 101, -86, 6, 14, 8, 1, 16, -40, -126, -27, -14, -12,
-87, -61, 2, -16, 1, 1, -110, 3, 93, 8, 100, 80, 0, -94, 6, 86, 34, 73, 36, 71, 80, 82,
77, 67, 44, 49, 48, 51, 50, 51, 49, 46, 54, 48, 49, 44, 86, 44, 53, 50, 48, 53, 46, 54, 52, 50,
54, 55, 48, 44, 78, 44, 48, 48, 54, 49, 57, 46, 54, 49, 51, 57, 52, 55, 44, 69, 44, 52, 51, 46,
50, 44, 51, 54, 46, 52, 44, 50, 51, 48, 49, 49, 53, 4, 4, 44, 44, 83, 42, 54, 68, 32, 74, 9, 69, 80,
83, 71, 58, 52, 51, 50, 54, -30, 3, 97, 10, 4, 78, 77, 69, 65, 18, 73, 36, 71, 80, 82, 77, 67, 44, 49,
48, 51, 50, 51, 49, 46, 54, 48, 49, 44, 86, 44, 53, 50, 48, 53, 4, 6, 54, 52, 50, 54, 55, 48, 44, 78,
44, 48, 48, 54, 49, 57, 46, 54, 49, 51, 57, 52, 55, 44, 69, 44, 52, 51, 46, 50, 44, 51, 54, 46, 52,
44, 50, 51, 48, 49, 49, 53, 44, 44, 44, 83, 42, 54, 68, 32, 82, 14, 10, 5, 8, 2, -80, 1, 2, -94, 6, 4, 8, 8, 16, 6 };
zmsg_addmem(msg, buf, 226);
zwssock_send(sock, &msg);
}
zwssock_destroy(&sock);
zctx_destroy(&ctx);
}
and following javascript:
var dealer = new JSMQ.Dealer();
dealer.connect("ws://localhost:86");
// we must wait for the dealer to be connected before we can send messages, any messages we are trying to send
// while the dealer is not connected will be dropped
dealer.sendReady = function() {
var message = new JSMQ.Message();
message.addString("Hello");
dealer.send(message);
};
dealer.onMessage = function (message) {
// the response from the server
var buffer = message.popBuffer();
console.log(buffer.length);
console.log(buffer);
};
function send() {
var message = new JSMQ.Message();
message.addString(document.getElementById("messageTextBox").value);
dealer.send(message);
}

Categories

Resources