How to add dynamic dataset using chart.js in ASP.NET MVC - javascript

I'm trying to display one pie chart for each question from my database. Right now, I am only able to display one chart on the first question.
I don't know how to display charts for the rest of the questions. I'm also not sure if I'm doing it the right way? I'm currently using ViewBag to pass the data from controller. How do I do it properly?
Please help me. Thanks.
This is my View:
<table class="table">
<tr>
<th>
Questions
</th>
</tr>
#foreach (var question in (List<Testv3.Models.MyViewModel>)ViewData["questionlist"])
{
<tr>
<td>
#question.Question
<br />
<div class="chart">
<canvas id="pie-chart"></canvas>
</div>
</td>
</tr>
}
</table>
#section Scripts {
<script type="text/javascript">
var PieChartData =
{
labels: ["Agree", "Somewhat Agree", "Disagree"],
datasets: [{
label: 'Overall report',
backgroundColor: [
"#f990a7",
"#aad2ed",
"#9966FF",
],
borderWidth: 2,
data: [#ViewBag.countAgree, #ViewBag.countSomewhatAgree, #ViewBag.countDisagree]
}]
};
window.onload = function () {
var ctx1 = document.getElementById("pie-chart").getContext("2d");
window.myBar = new Chart(ctx1,
{
type: 'pie',
data: PieChartData,
options:
{
responsive: true,
maintainAspectRatio: true
}
});
}
</script>
This is my controller:
List<PsychTestViewModel> questionlist = new List<PsychTestViewModel>();
var datalistQuestions = db.Questions.ToList();
foreach (var question in datalistQuestions)
{
PsychTestViewModel ptvm = new PsychTestViewModel();
ptvm.QuestionID = question.QuestionID;
ptvm.Question = question.Question;
questionlist.Add(ptvm);
ViewBag.questionlist = questionlist;
var agree = from ans in db.Answers
where ans.Answer == 1 && ans.QuestionID == ptvm.QuestionID
select new { Answer = ans.Answer };
var somewhatAgree = from ans in db.Answers
where ans.Answer == 2 && ans.QuestionID == ptvm.QuestionID
select new { Answer = ans.Answer };
var disagree = from ans in db.Answers
where ans.Answer == 3 && ans.QuestionID == ptvm.QuestionID
select new { Answer = ans.Answer };
int Agree = agree.Count();
int SomewhatAgree = somewhatAgree.Count();
int Disagree = disagree.Count();
ViewBag.countSomewhatAgree = SomewhatAgree;
ViewBag.countAgree = Agree;
ViewBag.countDisagree = Disagree;
}

Related

How to generate and show a bar diagram with using user given input while submitting [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I want to show a table that accepts input from the user for example the details of the country and the count of medals got in any champions league, and shows it as a bar diagram using javascript while submitting the form.
So here the example I prepared and working fine.
<!DOCTYPE HTML>
<html>
<head>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
</head>
<body>
<div id="tableClass">
<h1>Asia Olympics 2018</h1>
<label>Country : </label>
<input name="country" id="country"/></br>
<label>Gold : </label>
<input name="gold" id="goldcount" onkeyup="validNumber(this.value, goldcount)"/></br>
<label>Silver : </label>
<input name="silver" id="silvercount" onkeyup="validNumber(this.value, silvercount)"/></br>
<label>Bronze : </label>
<input name="bronze" id="bronzecount" onkeyup="validNumber(this.value, bronzecount)"/></br>
<p id="error_display"></p>
<button id="save" type="button" onclick="savedata()">Submit</button>
</div>
<div id="chartContainer" style="height: 300px; width: 100%;"></div>
</body>
<script>
// Validate number for medals count
function validNumber(val, number) {
number.value = val.replace(/[^0-9]/g, "");
}
let olympics = [];
// Save form data function
function savedata(){
let contry = document.getElementById('country').value;
let gold = document.getElementById('goldcount').value;
let silver = document.getElementById('silvercount').value;
let bronze = document.getElementById('bronzecount').value;
let error = document.getElementById('error_display');
error.style.display = 'none';
if(contry == '' || gold == '' || silver == '' || bronze == '') {
error.innerHTML = 'Please enter all the fileds!';
error.style.display = 'block';
error.style.color = 'red';
return false;
}
let obj = {contry, gold, silver,bronze};
olympics.push(obj);
localStorage.setItem('olympicsData', JSON.stringify(olympics));
contry = '';
gold = '';
silver = '';
bronze = '';
showGraph();
}
// Show the pie diagram chart
function showGraph() {
let details = JSON.parse(localStorage.getItem("olympicsData"));
let dps1 = [];
let dps2 = [];
let dps3 = [];
details.map((data) => {
dps1.push({y: parseInt(data.gold), label: data.contry});
dps2.push({y: parseInt(data.silver), label: data.contry});
dps3.push({y: parseInt(data.bronze), label: data.contry});
} )
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
title: {
text: "Asia Olympics - 2018"
},
data: [
{
type: 'bar',
yValueFormatString: "##\" Gold medals\"",
indexLabel: "{y}",
dataPoints: dps1
},
{
type: 'bar',
yValueFormatString: "##\" Silver medals\"",
indexLabel: "{y}",
dataPoints: dps2
},
{
type: 'bar',
yValueFormatString: "##\" Bronze medals\"",
indexLabel: "{y}",
dataPoints: dps3
}
]
});
chart.render();
}
</script>
</html>
I hope this will useful. Try it!

Chartjs Line Chart flickers between old and new data when hovering

My problem is not making the chart, but when I input new values for the start freq and end freq, which are the first and last values of my x-axis array after calling getFreq(), the chart glitches when I hover, going back and forth between the old data and new data. Can anyone help me figure out how to delete the old data and make/update to a new chart where the chart doesn't flicker? My code is shown below.
let Conductivity = document.getElementById('Conductivity');
let StartFreq = document.getElementById('StartFreq');
let StopFreq = document.getElementById('StopFreq');
let a = document.getElementById('a');
let b = document.getElementById('b');
let unitInch = document.getElementById('unitInch');
let test = document.getElementById('test');
let diameter = document.getElementById('Diameter');
let ctx = document.getElementById('myChart').getContext('2d');
function generateLabels(){
// To generate the xa xis intervals
let xaxis = [];
for (let i = 0; i <= 10; i++) {
let valToAppend = Math.round((parseFloat(StartFreq.value) + (parseFloat(StopFreq.value)-parseFloat(StartFreq.value)) / 10 * i)*100)/100;
if (valToAppend <= parseFloat(StopFreq.value)){
xaxis.push(valToAppend)
}
}
return xaxis
}
function getFreq(){
let x = generateLabels();
let freq = [];
let start = x[0];
freq.push(start);
let end = x[x.length - 1];
for (let i=0; i < 4 * (end-start);i++){
let lastfreq = freq[freq.length - 1];
freq.push(lastfreq + 0.25)
}
// let rklen = freq.length;
return freq
}
function getRS(){
let RS = [];
let freq = getFreq();
freq.forEach(element =>{
let RStoAppend = Math.sqrt((2*Math.PI*(Math.pow(10,9)*element)*(4*Math.PI*Math.pow(10,-7)))/(2*(parseFloat(Conductivity.value)*Math.pow(10,7)))) ;
RS.push(RStoAppend)
});
return RS
}
function getRK(){
let RK = [];
let freq = getFreq();
freq.forEach(element => {
let RKtoappend = (2*Math.PI*(element * Math.pow(10,9))) / (3* Math.pow(10,8));
RK.push(RKtoappend)
});
return RK
}
function getRbeta(){
let Rbeta = [];
let RK = getRK();
RK.forEach(element => {
let Rbetatoappend = Math.sqrt(Math.pow(element,2) - Math.pow((Math.PI/(parseFloat(a.value)*25.4/1000)),2));
Rbeta.push(Rbetatoappend);
});
return Rbeta;
}
function getRatte(){
let Ratte = [];
let RS = getRS();
let RK = getRK();
let Rbeta = getRbeta();
for (let i = 0; i < RS.length ;i++){
let Rattetoappend = RS[i]*(2*(25.4/1000*parseFloat(b.value))*Math.pow(Math.PI,2)+Math.pow((parseFloat(a.value)*25.4/1000),3)*Math.pow(RK[i],2))/(Math.pow((parseFloat(a.value)*25.4/1000),3)*(25.4/1000*parseFloat(b.value))*Rbeta[i]*RK[i]*377)/(1000/25.4);
Ratte.push(Rattetoappend);
}
// test.innerHTML = '<td id="test">' + Ratte + '<td>';
return Ratte
}
function getRTE10(){
let RTE10 = [];
let Ratte = getRatte();
Ratte.forEach(element => {
if (isNaN(-20*Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))) {
RTE10.push(0)
}
else {
RTE10.push(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))
}
});
return RTE10
}
//////////////////////// For CTE11/////////////
function getk(){
let k = [];
let freq = getFreq();
freq.forEach(element => {
k.push(2*Math.PI*element*Math.pow(10,9)/(3*Math.pow(10,8)))
});
return k
}
function getbeta(){
let beta = [];
let k = getk();
k.forEach(element => {
beta.push(Math.sqrt(Math.pow(element,2)-Math.pow((1.8412/(parseFloat(diameter.value)/2*25.4/1000)),2)))
});
return beta
}
function getTE11_1(){
let TE11_1 = [];
let k = getk();
let rs = getRS();
let beta = getbeta();
for (let i = 0; i < rs.length ;i++){
TE11_1.push(rs[i]*(Math.pow((1.8412/(parseFloat(diameter.value)/2*25.4/1000)),2)+Math.pow(k[i],2)/(Math.pow(1.8414,2)-1))/((parseFloat(diameter.value)/2*25.4/1000)*k[i]*beta[i]*377)/(1000/25.4));
}
return TE11_1
}
function getCTE11(){
let CTE11 = [];
let TE11_1 = getTE11_1();
TE11_1.forEach(element => {
if (isNaN(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))) {
CTE11.push(0)
}
else {
CTE11.push(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))
}
});
// test.innerHTML = '<td id="test">' + CTE11 + '<td>';
return CTE11
}
function getTM01(){
let TM01 = [];
let rs = getRS();
let freq = getFreq();
for (let i = 0; i < rs.length ;i++){
TM01.push(rs[i]/((parseFloat(diameter.value)/2 *25.4/1000)*377*Math.sqrt(1-Math.pow(((2.4049/(2*Math.PI*parseFloat(diameter.value)/2 *25.4/1000)*0.3)*Math.pow(10,9)/(freq[i]*Math.pow(10,9))),2)))/(1000/25.4));
}
return TM01
}
function getCTM01(){
let CTM01 = [];
let TM01 = getTM01();
TM01.forEach(element => {
if (isNaN(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))) {
CTM01.push(0)
}
else {
CTM01.push(-20 * Math.log10(Math.exp(-element)) * parseFloat(unitInch.value))
}
});
return CTM01
}
function getAt2(){
let at2 = [];
let freq = getFreq();
freq.forEach(element =>{
at2.push(Math.pow(((3.8318/(2*Math.PI*parseFloat(diameter.value)/2 *25.4/1000)*0.3)*Math.pow(10,9)/(element*Math.pow(10,9))),2)+1/(Math.pow(3.8318,2)-1))
});
return at2
}
function getAt1(){
let at1 = [];
let freq = getFreq();
let rs = getRS();
for (let i = 0; i < rs.length ;i++){
at1.push(rs[i]/(parseFloat(diameter.value)/2 *25.4/1000*377*Math.sqrt(1-Math.pow(((3.8318/(2*Math.PI*parseFloat(diameter.value)/2 *25.4/1000)*0.3)*Math.pow(10,9)/(freq[i]*Math.pow(10,9))),2)))/(1000/25.4));
}
return at1
}
function getCTE01(){
let CTE01 = [];
let at1 = getAt1();
let at2 = getAt2();
for(let i = 0;i < at1.length; i++){
if (isNaN((-20*Math.log10(Math.exp(-(at1[i]*at2[i])))*parseFloat(unitInch.value)))) {
CTE01.push(0)
}
else {
CTE01.push(-20 * Math.log10(Math.exp(-(at1[i] * at2[i]))) * parseFloat(unitInch.value))
}
}
return CTE01
}
function getdata(){
let data =[];
let xaxis = getFreq();
let RTE10 = getRTE10();
let CTE11 = getCTE11();
let CTM01 = getCTM01();
let CTE01 = getCTE01();
data.push(xaxis,RTE10,CTE11,CTM01,CTE01);
return data
}
function draw_chart(data) {
let chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: data[0],
datasets: [{
label: 'R-TE10',
data: data[1],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'blue',
pointRadius: '0'
},{
label: 'C-TE11',
data: data[2],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'orange',
pointRadius: '0'
},{
label: 'C-TM01',
data: data[3],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'green',
pointRadius: '0'
},{
label: 'C-TE01',
data: data[4],
pointStyle : 'line',
backgroundColor: 'transparent',
borderColor: 'red',
pointRadius: '0'
}]
},
// Configuration options go here
options: {
responsive : true,
scales: {
xAxes :[{
ticks: {
min: StartFreq,
max: StopFreq,
suggestedMin: StartFreq,
suggestedMax: StopFreq,
stepSize: 0.25,
}
}],
yAxes: [{
ticks: {
min:0,
max:10,
suggestedMin: 0,
suggestedMax: 10,
maxTicksLimit: 11,
stepSize : 1,
beginAtZero: true,
}
}]
}
}
});
}
function generateChart() {
// removeData(chart);
let data = getdata();
draw_chart(data);
}
HTML
<table class="inner">
<tr class="inner">
<td class="inner"> Attenuation (air) /</td>
<td class="inner"> <input class="numInput" type="number" id="unitInch"/></td>
<td class="inner">(in inches)</td>
</tr>
<tr class="inner">
<td class="inner" colspan="2">Rectangular WG</td>
<td class="inner">Circular WG</td>
<td class="inner">Material</td>
</tr>
<tr class="inner">
<td class="inner">a (inch)</td>
<td class="inner">b (inch)</td>
<td class="inner">Diameter (inch)</td>
<td class="inner">Conductivity ( x 10<sup>7</sup> S/m)</td>
<td class="inner">Start Freq (GHz)</td>
<td class="inner">Stop Freq (GHz)</td>
</tr>
<tr class="inner">
<td class="inner"><input class="numInput" type="number" id='a'/></td>
<td class="inner"><input class="numInput" type="number" id="b"/></td>
<td class="inner"><input class="numInput" type="number" id="Diameter"/></td>
<td class="inner"><input class="numInput" type="number" id="Conductivity"/></td>
<td class="inner"><input class="numInput" type="number" id="StartFreq"/></td>
<td class="inner"><input class="numInput" type="number" id="StopFreq"/></td>
</tr>
</table>
<button onclick="generateChart()"><strong>Generate Chart</strong></button>
<div id="chartsize">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.js"></script>
<script src="js/chart.js"></script>
**By the way, my chart works completely fine the first time I load the page, then when I update, the chart flickers like crazy when hovering.
I added in a lot more code, so that you guys can recreate the chart and figure it out. Please ignore the bad style, I am new to Web Development...
**
This seems to be a somewhat common issue with Chart.js. The typical suggested solutions are to either destroy the chart instance, or remove the canvas element and create a new one whenever the chart is updated.
For the first possible solution, you can try calling destroy() on your chart object. For example, if your chart object is chart, you could call chart.destroy();. From the documentation:
Use this to destroy any chart instances that are created. This will
clean up any references stored to the chart object within Chart.js,
along with any associated event listeners attached by Chart.js. This
must be called before the canvas is reused for a new chart.
However, this doesn't seem to always work. Removing and creating the canvas element seemed to work when I tested it with your code. You could use a function like below and call it whenever you click the "Generate Chart" button:
function resetCanvas (){
$("canvas").remove();
$("#chartsize").append('<canvas id="myChart"><canvas>');
canvas = document.querySelector("#myChart");
ctx = canvas.getContext("2d");
};
Note that you might need to set the height and width of your chart container. I'm using jQuery for this function for simplicity. But you could reproduce it using vanilla JS if needed.
See the fiddle here for an example of this using your code: https://jsfiddle.net/fL1rd3wp/1/

Display a comparison table

I have a html table with each column displaying a company and each row has a feature that offers this company.
Let's say
Company A has features 1,2,3 and features 8,9 optional.
Company B has features 1,3 and features 7,8 optional.
Company C has features 3,4 and features 9,10 optional.
//A B C
//-------------
//1 | Y Y X
//2 | Y X X
//3 | Y Y Y
//4 | X X Y
//7 | X O X
//8 | O O X
//9 | O X O
//10 | X X O
I dont display features 5,6 because they are missing in all companies.
I want the table to display "fa-check"(Y) when the company contains the feature, "fa-times"(X) when is missing and input type="checkbox" when the feature is optional. Each optional feature has a price so the total price for a company is recalculated when is checked
<table>
<thead>
<tr>
<!-- ko foreach : companies -->
<th data-bind="text: name"></th>
<!-- /ko -->
</tr>
</thead>
<tbody>
<!-- ko foreach : UnionOfFeatures-->
<tr>
<!-- ko foreach : companies -->
<td data-bind="if: mandatory"><i class="fa fa-check"></i></td>
<td data-bind="ifnot: mandatory"><input type="checkbox" data-bind="checked: Checked"></td>
#*<td data-bind="when is Missing"><i class="fa fa-times"></i></td>*#
<!-- /ko -->
</tr>
<!-- /ko -->
</tbody>
<script type="text/javascript">
function feature(id, mandatory) {
var self = this;
self.id = id;
self.mandatory = ko.observable(mandatory);
}
function company(name, features) {
var self = this;
self.name = name;
self.features = ko.observableArray(features);
}
var viewModel = function () {
self.companies = ko.observableArray(
[
new company("Company 1", [
new feature(1, true),
new feature(2, true),
new feature(3, true),
new feature(8, false),
new feature(9, false)
]),
new company("Company 2", [
new feature(1, true),
new feature(3, true),
new feature(7, false),
new feature(8, false)
]),
new company("Company 3", [
new feature(3, true),
new feature(4, true),
new feature(9, false),
new feature(10, false)
]),
]);
self.UnionFeaturesIds = ko.computed(function () {
return 0; //????;
});
}
ko.applyBindings(new viewModel());
You're missing var self = this inside your viewModel.
I've had a quick play with this, and I decided to do it in slightly different way. Feel free to change any of my code, I'm just having fun ;p
I've produced an array of all features, which I can always reference. Then I created a new helper logic inside each company that will loop through all features.
If a given feature is found, it's then added, otherwise we create a dummy object that we know is a missing feature (I've added ID of -1)
var allFeatures = ko.observableArray();
function feature(id, mandatory) {
var self = this;
self.id = id;
self.mandatory = ko.observable(mandatory);
}
function company(name, features) {
var self = this;
self.name = name;
self.features = ko.observableArray(features);
}
var viewModel = function() {
var self = this;
self.companies = ko.observableArray(
[
new company("Company 1", [
new feature(1, true),
new feature(2, true),
new feature(3, true),
new feature(8, false),
new feature(9, false)
]),
new company("Company 2", [
new feature(1, true),
new feature(3, true),
new feature(7, false),
new feature(8, false)
]),
new company("Company 3", [
new feature(3, true),
new feature(4, true),
new feature(9, false),
new feature(10, false)
])
]);
self.setFeatures = function(features) {
var featuresToChange = features;
var tempFeatures = [];
// loop through all features, so we can create all rows in the HTML
for (var i = 0; i < allFeatures().length; i++) {
var currentFeature = featuresToChange()[i];
// see if current feature exists in a given company
var featureWithIdFound = ko.utils.arrayFirst(featuresToChange(), function(item) {
return item.id === allFeatures()[i];
});
// if the feature was found, and we are currently looping through its ID, push it to temporary array
if (featureWithIdFound !== null && featureWithIdFound.id === allFeatures()[i]) {
tempFeatures.push(featureWithIdFound);
} else {
// otherwise push a feature that's missing, by giving it's negative ID
tempFeatures.push(new feature(-1));
}
}
// push to existing features array in that company
featuresToChange(tempFeatures);
}
self.createAllFeaturesList = function() {
var _allFeatures = [];
// loop through all companies to get unique features
for (var i = 0; i < self.companies().length; i++) {
var curCompany = self.companies()[i];
// push all unique items to temporary array called _allFeatures
ko.utils.arrayFirst(curCompany.features(), function(item) {
if (_allFeatures.indexOf(item.id) < 0 && item.id !== -1) {
// only push items that don't exist in the array, so we don't end up with duplicated
_allFeatures.push(item.id);
}
});
}
// sort IDs
_allFeatures.sort(function(a, b) {
return a > b ? 1 : -1
});
allFeatures(_allFeatures);
ko.utils.arrayForEach(self.companies(), function(item) {
// apply them to table
self.setFeatures(item.features);
});
};
// instantiate features
self.createAllFeaturesList();
}
ko.applyBindings(new viewModel());
.fa-check {
color: green;
}
.fa-times {
color: red;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.1/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<table>
<thead>
<tr data-bind="foreach: companies">
<th data-bind="text: name"></th>
</tr>
</thead>
<tbody>
<tr data-bind="foreach: companies">
<td>
<table>
<tbody data-bind="foreach: features">
<tr>
<td>
<i class="fa fa-check" data-bind="visible: mandatory"></i>
<input type="checkbox" data-bind="visible: !mandatory() && id > 0"/>
<i class="fa fa-times" data-bind="visible: id < 0"></i>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
I hope that this helps.

How to show php dynamic array data in c3js chart?

I have multidimensional array($array) like this,
{
"2015-11-17": {
"department1":"0.5700",
"department3":"0.0000"
},
"2015-11-18": {
"department1":"0.5700"
},
"2015-11-20": {
"department1":"0.0000"
},
"2015-11-23": {
"department1":"1.7100",
"department2":"1.7100",
"department3":"2.8500",
}
.
.
.
}
This is a dynamic array and that data are get from database. All data are exists in $array variable. The above data are more than that. I just show a little, because the data are get from database.
I want to show that data on c3js chart like this format,
json:[{
"date": "2015-11-17",
"department1": ""0.5700"",
"department2": "0.0000",
"department3": "0.0000",
"department4": "0.0000",
}],
And I need to show four department data for each date.
In the array, you can see some day have one or two department. I want to add all four department for each day when I change above json format to show in chart.
For example, in 2015-11-17, it has department1 and 3. I want to add next department2 and 4 with '0' in this day.
I want to add another department for each day just like that.
When I try to change $array to above format, I don't get the correct result.
Here is what I try,
<div id='chart'></div>
<script>
var chart = c3.generate({
bindto: '#chart',
data: {
x: 'date',
xFormat: '%Y-%m-%d',
json:[
<?php
for ($i = 0; $i < count($array); $i++) {
$key=key($array);
$val=$array[$key];
if ($val<> ' ') {
foreach ($val as $k=>$v) {
?>
{
'date':<?php echo $key?>,
<?php echo $k?> : <?php echo $v?>,
},
<?php
}
}
next($array);
}
?>],
},
legend: {
position: 'right',
},
line: {
width:0.5
},
axis: {
x: {
type: 'timeseries',
tick:{
format: '%Y-%m-%d',
rotate: 75,
},
label: {
text: 'Date',
position: 'outer-center'
}
}
},
grid: {
y: {
show:true,
}
},
});
</script>
So, now I have problem to show array data in chart. I'm very appreciate for any answer and suggestion.
Here is the sample of dynamic chart image of what I want,
Kindly check the below code. Points to note:
- $deptNames = array of department names as shown in example output.
- $dataArray = is the array which comes from database directly
- instead of echoing output you can save it to any variable and access accordingly.
$deptNames = array('department1','department2','department3','department4');
$resultArray = array();
$index = 0;
foreach($dataArray as $date => $data) {
$resultArray[$index] = array();
if(is_array($data)) {
$dataDeptNames = array_keys($data);
$diff = array_diff($deptNames,$dataDeptNames);
if($diff && count($diff) > 0) {
foreach($diff as $notExistDept) {
$data[$notExistDept] = "0.0000";
}
}
$resultArray[$index] = $data;
$resultArray[$index]['date'] = $date;
ksort($resultArray[$index]);
}
$index++;
}
echo json_encode($resultArray);
It will give you output as:
[
{
"date":"2015-11-17",
"department1":"0.5700",
"department2":"0.0000",
"department3":"0.0000",
"department4":"0.0000"
},
{
"date":"2015-11-18",
"department1":"0.5700",
"department2":"0.0000",
"department3":"0.0000",
"department4":"0.0000"
},
{
"date":"2015-11-20",
"department1":"0.0000",
"department2":"0.0000",
"department3":"0.0000",
"department4":"0.0000"
},
{
"date":"2015-11-23",
"department1":"1.7100",
"department2":"1.7100",
"department3":"2.8500",
"department4":"0.0000"
}
]
Well if you get the array and is stored in a variable, then you can use this pure JS function to convert it to the format you need:
var convertArr = function(x){
var y = [];
for (var k1 in x) {
if (x.hasOwnProperty(k1)) {
var obj = {};
obj['date'] = k1;
var tmp = [];
for (var k2 in x[k1]){
if (x[k1].hasOwnProperty(k2)){
tmp.push(k2[k2.length-1]);
obj[k2] = x[k1][k2];
}
}
var no = ["1","2","3","4"];
var tmpSet = new Set(tmp);
var noSet = new Set(no);
var diff = no.filter(function(z) { return !tmpSet.has(z); })
.concat(tmp.filter(function(z){ return !noSet.has(z); }));
for (var i = 0; i < diff.length; i++){
obj['department'+diff[i]] = '0.0000';
}
y.push(obj);
}
}
return y;
}
From there you can proceed.
Hope it helps.

Angular JS: Multiple Data Bindings Into Table

Okay. I'm pulling together a data table that is going to look through majors and minors of a school. I'm running into issues of trying not to repeat myself in the data where every possible, but am not sure how to get the data pulled into the document, or even how to setup the data into the different arrays. Looking for some advice and help in whichever of these two areas I can find. When I search through docs and API's none of them seem to go deep enough into the data to really get what I'm looking to accomplish.
I have made a plunker to showcase my problem more clearly, or at least I hope to make it clearer.
http://plnkr.co/edit/2pDmQKKwjO6KVullgMm5?p=preview
EDIT:
It would even be okay with me if the degree each degree could be read as a boolean, and same with Education level. I'm just not sure how to go about it without repeating the whole line in a new table row. http://www.clemson.edu/majors
HERE IS THE HTML
<body ng-app="app">
<h2> Majors and Minors </h2>
<table ng-controller="MajorsCtrl">
<tbody>
<tr>
<th>Department</th>
<th>Major</th>
<th>Education Level</th>
<th>Location </th>
<th>Degree</th>
<th>Department Website </th>
</tr>
<tr ng-repeat="major in majors">
<td>{{major.Department}}</td>
<td>{{major.Major}}</td>
<td>{{major.EdLevel}}</td>
<td>{{major.Type}}</td>
<td>{{major.Degree}}</td>
<td>{{major.Website}}</td>
</tr>
</tbody>
</table>
</body>
HERE IS THE JS
var app = angular.module('app', []);
// Majors and Minors Data That will be injected into Tables
app.controller('MajorsCtrl', function($scope) {
// Heres where it gets tricky
// Now I have biology with four diff degree types
// Biology with 2 diff EdLevels
// How do I combine all of these into 1 Group without repeating
var majorsInfo = [
{
Department:'Statistics',
Major:'Applied Statitistics',
EdLevel:'Graduate',
Type:'Campus/Online',
Degree:'Graduate Certificate',
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Graduate',
Type:'Campus',
Degree:'PH.D' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Graduate',
Type:'Campus',
Degree:'M.S' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Undergraduate',
Type:'Campus',
Degree:'B.A.' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Undergraduate',
Type:'Campus',
Degree:'B.S.' ,
Website: 'http://biology.wvu.edu',
},
];
$scope.majors = majorsInfo;
});
This seems to be a question about modeling the data. I took a few assumptions:
A department can offer multiple majors
A department has a website
Each major can offer one to many Educations (i.e. Education Level, On/Off Campus, Degree)
The department can offer multiple minors with the same data structure as majors
I modeled a set of "enums" and Programs/Departments after your data. I used enums for ease of updating the values in multiple locations:
app.factory("EducationEnums", function () {
var EdLevels = {
GRAD: "Graduate",
UGRAD: "Undergraduate"
};
var Types = {
CAMPUS: "Campus",
ONLINE: "Online",
HYBRID: "Campus/Online"
};
var Degrees = {
PHD: "PH.D",
MS: "M.S.",
BS: "B.S.",
BA: "B.A.",
GCERT: "Graduate Certificate"
};
return {
EdLevels: EdLevels,
Types: Types,
Degrees: Degrees
}
});
app.factory("Programs", function (EducationEnums) {
var EdLevels = EducationEnums.EdLevels;
var Types = EducationEnums.Types;
var Degrees = EducationEnums.Degrees;
return [
{
Department: "Biology",
Website: "http://biology.wvu.edu",
//Majors offered by department
Majors: [{
Major: "Biology",
Education: [
{
EdLevel: EdLevels.GRAD,
Type: Types.CAMPUS,
Degree: Degrees.PHD
},
{
EdLevel: EdLevels.GRAD,
Type: Types.CAMPUS,
Degree: Degrees.MS
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BA
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BS
}
]
}],
Minors: [{
//Minors can go here
}]
},
{
Department: "Statistics",
Website: "http://biology.wvu.edu",
Majors: [{
Major: "Applied Statistics",
Education: [
{
EdLevel: EdLevels.GRAD,
Type: Types.HYBRID,
Degree: Degrees.GCERT
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BS
}
]
}],
Minors: [{
//Minors can go here
}]
}
]
});
Next, I made a Majors service that uses this Programs data to build ViewModels (to be bound to scope in the controllers). Here you can build your original table, or you can build a matrix (like the Clemson site):
app.service("Majors", function (Programs, EducationEnums) {
var Degrees = this.Degrees = EducationEnums.Degrees;
//Build ViewModel for all details
this.getMajorDetails = function () {
var arr = [];
var programLen;
var majorLen;
var eduLen;
for (var i = 0; i < (programLen = Programs.length); ++i) {
var p = Programs[i];
var dept = p.Department;
var ws = p.Website;
var Majors = p.Majors;
for (var j = 0 ; j < (majorLen = Majors.length); ++j) {
var maj = Majors[j].Major;
var edu = Majors[j].Education;
for (var k = 0; k < (eduLen = edu.length); ++k) {
arr.push({
Department: dept,
Major: maj,
EdLevel: edu[k].EdLevel,
Type: edu[k].Type,
Degree: edu[k].Degree,
Website: ws
});
}
}
}
return arr;
}
//Build ViewModel for Degrees offered (similar to Clemson)
this.getMajorMatrix = function () {
var arr = [];
var programLen;
var majorLen;
var eduLen;
for (var i = 0; i < (programLen = Programs.length); ++i) {
var p = Programs[i];
var Majors = p.Majors;
for (var j = 0; j < (majorLen = Majors.length); ++j) {
var maj = Majors[j].Major;
var edu = Majors[j].Education;
var obj = {
Major: maj
};
for (var k = 0; k < (eduLen = edu.length); ++k) {
var degree = edu[k].Degree;
if (degree === Degrees.PHD) {
obj.PHD = true;
}
else if (degree === Degrees.MS) {
obj.MS = true;
}
else if (degree === Degrees.BS) {
obj.BS = true;
}
else if (degree === Degrees.BA) {
obj.BA = true;
}
}
arr.push(obj);
}
}
return arr;
}
});
Your controller can just call the Majors service methods to bind the ViewModel to the $scope:
app.controller('MajorsCtrl', function($scope, Majors) {
$scope.majorDetails = Majors.getMajorDetails();
});
app.controller("MajorMatrixCtrl", function ($scope, Majors) {
$scope.Degrees = Majors.Degrees;
$scope.majorMatrix = Majors.getMajorMatrix();
});
Separting like this would allow you to later update the Programs factory to not just use static data, but could pull from a service via $http for instance. The Programs data can be manipulated to achieve your desired ViewModel through the Majors service (and Minors service if you choose to write a separate one).
Updated Plunkr

Categories

Resources