Chartjs Line Chart flickers between old and new data when hovering - javascript

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/

Related

Async/await function to show, wait, hide overlay not working in javascript

I'm having a problem with showing an overlay div element and then hiding it again after the runSearch() function has completed. In short, the overlay does not appear at all.
What the overlay should look like if it worked:
If I had to guess, I believe it could relate to a misunderstanding about how to implement async/await correctly in javascript.
Since I am limited for space here, the full Github project is accessible as a fully deployed page here, if you need more context. However, the most relevant excerpts are below:
The overlay div element in index.html:
<div class="overlay d-flex justify-content-center align-items-center">
<h5>Please wait...</h5>
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
The overlay in CSS:
.overlay {
background-color:#EFEFEF;
position: fixed;
width: 100%;
height: 100%;
z-index: 1000;
left: 0px;
display: none!important;
/* without !important, the overlay would immediately kick into effect */
}
The JS functions which show and hide the overlay when called upon:
function loadingOverlayOn() {
document
.getElementsByClassName("overlay")[0]
.style.display = 'block'
}
function loadingOverlayOff() {
document
.getElementsByClassName("overlay")[0]
.style.display = 'none'
}
JS with respect to button #1:
cityInstanceBtn.addEventListener('click',async function(e){
// for use in headings inside runSearch
// reset
globalCityName === null;
globalCityState === null;
globalCityCountry === null;
globalCityName = e.target.dataset.city
globalCityState = e.target.dataset.state
globalCityCountry = e.target.dataset.country
loadingOverlayOn();
await runSearch(cityName, cityState, cityCountry, cityLat, cityLng, units)
loadingOverlayOff();
})
JS with respect to button #2, which occurs inside of a temporarily displayed Bootstrap modal:
cityInstanceBtn.addEventListener('click', async function(){
myModal.hide()
globalCityName = document.getElementById(id).dataset.city
globalCityState = document.getElementById(id).dataset.state
globalCityCountry = document.getElementById(id).dataset.country
loadingOverlayOn();
await runSearch(cityName, cityState, cityCountry, cityLat, cityLng, units)
loadingOverlayOff();
})
The JS function during which the overlay should be shown, and hidden once its execution is complete:
async function runSearch(
cityName,
cityState,
country,
cityLat,
cityLng,
detectedUnits
) {
console.log("check cityState: " + cityState);
console.log("check globalCityState: " + globalCityState);
var h2Today = document.getElementById("today-title");
var h2Next5Days = document.getElementById("next-5-days-title");
if (globalCityState != "undefined" && globalCityName && globalCityCountry) {
h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName}, ${globalCityState}, ${globalCityCountry}</span>`;
h2Next5Days.innerHTML = `<span class="orange">4-day</span> outlook for <span class="cornflowerblue">${globalCityName}, ${globalCityState}, ${globalCityCountry}</span>`;
} else if (
(globalCityState = "undefined" && globalCityName && globalCityCountry)
) {
h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName},${globalCityCountry}</span>`;
h2Next5Days.innerHTML = `<span class="orange">4-day</span> outlook for <span class="cornflowerblue">${globalCityName}, ${globalCityCountry}</span>`;
}
var newSearchObject = {
cityName: cityName,
cityState: cityState,
cityCountry: country,
cityLat: cityLat,
cityLng: cityLng,
detectedUnits: detectedUnits,
};
var retrievedLocalStorage = localStorage.getItem("savedCities");
retrievedLocalStorage = JSON.parse(retrievedLocalStorage);
// const arr = retrievedLocalStorage.map(a => {a.cityLat, a.cityLng})
if (retrievedLocalStorage === null) {
localStorage.setItem("savedCities", JSON.stringify([newSearchObject]));
generatePrevCitiesList();
} else if (
retrievedLocalStorage.length > 0 &&
retrievedLocalStorage.length < 5
) {
retrievedLocalStorage.reverse();
if (
!retrievedLocalStorage.some((s) => {
return (
s.cityLat == newSearchObject.cityLat &&
s.cityLng == newSearchObject.cityLng
);
})
) {
// Check if an array of objects contains another object: https://stackoverflow.com/a/63336477/9095603
// this solution which converts objects to string first isn't entirely reliable if you can't guarantee the same order is preserved, for example: https://stackoverflow.com/a/201305/9095603
retrievedLocalStorage.push(newSearchObject);
retrievedLocalStorage.reverse();
console.log("existingSearchObject2: " + retrievedLocalStorage);
localStorage.setItem(
"savedCities",
JSON.stringify(retrievedLocalStorage)
);
}
generatePrevCitiesList();
} else if (retrievedLocalStorage.length >= 5) {
retrievedLocalStorage.reverse();
if (
!retrievedLocalStorage.some((s) => {
return (
s.cityLat == newSearchObject.cityLat &&
s.cityLng == newSearchObject.cityLng
);
})
) {
retrievedLocalStorage.push(newSearchObject);
}
while (retrievedLocalStorage.length > 5) {
retrievedLocalStorage.shift();
}
retrievedLocalStorage.reverse();
localStorage.setItem("savedCities", JSON.stringify(retrievedLocalStorage));
generatePrevCitiesList();
}
fetch(
`https://api.openweathermap.org/data/2.5/forecast?lat=${cityLat}&lon=${cityLng}&units=${detectedUnits}&appid=${apiKey}`
)
.then((response) => response.json())
.then((data) => {
console.log(data);
console.table(data.list);
console.log(JSON.stringify(data));
var timezone = data.city.timezone;
console.log({ timezone });
var country = data.city.country;
console.log({ country });
var cityName = data.city.name;
console.log({ cityName });
var datesArray = [];
console.log({ datesArray });
const days = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
// var h2Today = document.getElementById('today-title')
// h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName}, ${globalCityState}, ${globalCityCountry}</span>`
// }
// h2Today.innerHTML = `<span class="orange">Today's</span> forecast for <span class="cornflowerblue">${globalCityName},${globalCityCountry}</span>`
// }
for (let i = 0; i < data.list.length; i++) {
var unixTimestamp = data.list[i].dt;
console.log(data.list[i].dt);
// you don't need it for dt_txt but if you want to use the unix timestamp in the data, you can do this conversion:
var jsTimestamp = unixTimestamp * 1000;
var date = new Date(jsTimestamp);
var basicDateLocalAU = date.toLocaleDateString("en-AU");
var basicDateLocalUS = date.toLocaleDateString("en-US");
var basicDateLocalUser = date.toLocaleDateString(`en-${country}`);
console.log(basicDateLocalAU); // Prints: 5/6/2022
console.log(basicDateLocalUS); // Prints: 6/5/2022
console.log(basicDateLocalUser); // Prints: 6/5/2022
var timeLocalAU = date.toLocaleTimeString("en-AU", {
hour: "2-digit",
minute: "2-digit",
}); // Prints: 13:10:34
// https://stackoverflow.com/a/20430558/9095603
// https://bobbyhadz.com/blog/javascript-typeerror-date-getday-is-not-a-function#:~:text=getDay%20is%20not%20a%20function%22%20error%20occurs%20when%20the%20getDay,method%20on%20valid%20date%20objects.
data.list[i].basicDateLocalAU = basicDateLocalAU;
data.list[i].basicDateLocalUS = basicDateLocalUS;
data.list[i].basicDateLocalUser = basicDateLocalUser;
data.list[i].dayOfWeekIndex = date.getDay();
data.list[i].dayOfWeekValue = days[date.getDay()];
data.list[i].basicTime = timeLocalAU;
// https://bobbyhadz.com/blog/javascript-array-push-if-not-exist
if (!datesArray.includes(basicDateLocalUser)) {
datesArray.push(basicDateLocalUser);
var dayOfWeek = days[date.getDay()];
console.log(dayOfWeek);
}
}
console.log({ date });
console.log({ data });
var datalist = data.list;
console.log({ datalist });
var obj = groupBy(datalist, "basicDateLocalAU");
console.log({ obj });
// const result = data.list.group(({ basicCalendarDateAU }) => basicCalendarDateAU);
for (let i = 0; i < obj.length; i++) {
var dayTableEle = document.querySelector(`#day${i} table`);
// var textNode = document.createTextNode(`${dayOfWeekValue}`);
dayTableEle.innerHTML = `<row><th>Time</th><th>Temp</th><th></th><th>Conditions</th><th>Humidity</th><th>Wind speed</th></row>`;
for (let j = 0; j < obj[i].length; j++) {
console.log(obj[i].length);
if (!document.querySelector(`#day${i} h5`).innerText) {
document.querySelector(
`#day${i} h5`
).innerText = `${obj[i][j].dayOfWeekValue}`;
}
if (
!document.querySelector(`#day${i} span#usercountry-dateformat`)
.innerText
) {
document.querySelector(
`#day${i} span#usercountry-dateformat`
).innerText = `${obj[i][j].basicDateLocalUser}`;
}
if (
!document.querySelector(`#day${i} span#AU-dateformat`).innerText
) {
document.querySelector(
`#day${i} span#AU-dateformat`
).innerText = `${obj[i][j].basicDateLocalAU}`;
document
.querySelector(`#day${i} span#AU-dateformat`)
.style.setProperty("display", "none");
}
if (
!document.querySelector(`#day${i} span#US-dateformat`).innerText
) {
document.querySelector(
`#day${i} span#US-dateformat`
).innerText = `${obj[i][j].basicDateLocalUS}`;
document
.querySelector(`#day${i} span#US-dateformat`)
.style.setProperty("display", "none");
}
// var kelvinToCelcius = obj[i][j].main.temp - 273.15;
var tempMetric;
var tempImperial;
var windSpeedImperial;
var windSpeedMetric;
if (units == "metric") {
var tempMetric = obj[i][j].main.temp;
tempMetric = roundedToFixed(tempMetric, 1);
var tempImperial = tempMetric * 1.8 + 32;
tempImperial = roundedToFixed(tempImperial, 1);
var windSpeedMetric = obj[i][j].wind.speed;
windSpeedMetric = roundedToFixed(windSpeedMetric, 1);
var windSpeedImperial = windSpeedMetric * 2.23694;
windSpeedImperial = roundedToFixed(windSpeedImperial, 1);
var metricDisplay = "inline";
var imperialDisplay = "none";
} else if (units == "imperial") {
var tempImperial = obj[i][j].main.temp;
tempImperial = roundedToFixed(tempImperial, 1);
var tempMetric = (tempImperial - 32) / 1.8;
tempMetric = roundedToFixed(tempMetric, 1);
var windSpeedImperial = obj[i][j].wind.speed;
windSpeedImperial = roundedToFixed(windSpeedImperial, 1);
var windSpeedMetric = windSpeedImperial / 2.23694;
windSpeedMetric = roundedToFixed(windSpeedMetric, 1);
var metricDisplay = "none";
var imperialDisplay = "inline";
}
dayTableEle.innerHTML += `
<row>
<td id="tdTime">${obj[i][j].basicTime}</td>
<td id="tdTemp">
<span class="temp-metric metric" style="display:${metricDisplay};">${tempMetric} ${tempUnitsMetric}</span>
<span class="temp-imperial imperial" style="display:${imperialDisplay};">${tempImperial} ${tempUnitsImperial}</span>
</td>
<td><img src="https://openweathermap.org/img/wn/${obj[i][j].weather[0].icon}.png" alt="weather icon"></td>
<td id="tdConditions">${obj[i][j].weather[0].description}</td>
<td id="tdHumidity">${obj[i][j].main.humidity} %</td>
<td id="tdWindSpeed">
<span class="windspeed-metric metric" style="display:${metricDisplay};">${windSpeedMetric} ${windSpeedUnitsMetric}</span>
<span class="windspeed-imperial imperial" style="display:${imperialDisplay};">${windSpeedImperial} ${windSpeedUnitsImperial}</span>
</td>
<td id="tdWindDir"><i style="transform: rotate(${obj[i][j].wind.deg}deg)" class="fa-solid fa-arrow-up"></i></td>
</row>
`;
}
}
});
}
We can see here that the event listener is properly attached - this is true of both buttons but I'll show one here just to be representative:
Full Github project is accessible as a fully deployed page here.
To reiterate, the problem is that the overlay does not appear at all during this sequence of events and I'm seeing page elements prematurely before the page is built:
loadingOverlayOn();
await runSearch(cityName, cityState, cityCountry, cityLat, cityLng, units)
loadingOverlayOff();
You are not awaiting fetch, you are using then instead.
You have to await fetch
See below example
const response = await fetch(url);
const jsonData = await response.json()

Interact between values

I'm wondering how to stop counting money (iloscPieniedzy) when HP (iloscZycia) is 0 in this code:
let iloscZycia = 20;
const sumaZycia = document.getElementById("suma-zycia");
const dodajZycie = document.getElementById('dodaj-zycie');
const odejmijZycie = document.getElementById('odejmij-zycie');
dodajZycie.addEventListener("click", function() {
iloscZycia++;
sumaZycia.textContent = iloscZycia;
});
odejmijZycie.addEventListener("click", function() {
iloscZycia = iloscZycia - 5;
if (iloscZycia <= 0) {
iloscZycia = 0
};
sumaZycia.textContent = iloscZycia;
});
let iloscPieniedzy = 0;
const sumaPieniedzy = document.getElementById("suma-pieniedzy");
const dodajPieniadze = document.getElementById('dodaj-pieniadze');
const odejmijPieniadze = document.getElementById('odejmij-pieniadze');
dodajPieniadze.addEventListener("click", function() {
iloscPieniedzy = iloscPieniedzy + 10;
sumaPieniedzy.textContent = iloscPieniedzy;
});
odejmijPieniadze.addEventListener("click", function() {
iloscPieniedzy = iloscPieniedzy - 1;
if (iloscPieniedzy <= 0) {
iloscPieniedzy = 0
};
sumaPieniedzy.textContent = iloscPieniedzy;
});
I tried something like this:
if (sumaZycia=0){
sumaPieniedzy=0
};
but even this doesn't work like it's not connected.
the = operator is used to assign values to variables what you're looking for is the equality operator ===.
so try it like this:
if (iloscZycia === 0){
iloscPieniedzy = 0
};
Because Stack Overflow is an English language site, I've renamed your variables and created a map of the new names to previous names in comments at the top of the JavaScript below.
If you create a functional closure for updating your numeric variables, you can encapsulate the necessary logic for only updating money when hp is not equal to 0.
Here's a working example in a code snippet:
// hp: iloscZycia
// element1: sumaZycia
// element2: dodajZycie
// element3: odejmijZycie
// money: iloscPieniedzy
// element4: sumaPieniedzy
// element5: dodajPieniadze
// element6: odejmijPieniadze
let hp = 20;
const adjustHp = (amount) => {
hp += amount;
if (hp < 0) hp = 0;
element1.textContent = hp;
};
const element1 = document.getElementById("suma-zycia");
const element2 = document.getElementById("dodaj-zycie");
const element3 = document.getElementById("odejmij-zycie");
element1.textContent = hp;
element2.addEventListener("click", () => adjustHp(1));
element3.addEventListener("click", () => adjustHp(-5));
let money = 0;
const adjustMoney = (amount) => {
// Update money, but ONLY if hp is not 0:
if (hp !== 0) {
money += amount;
if (money < 0) money = 0;
}
element4.textContent = money;
};
const element4 = document.getElementById("suma-pieniedzy");
const element5 = document.getElementById("dodaj-pieniadze");
const element6 = document.getElementById("odejmij-pieniadze");
element4.textContent = money;
element5.addEventListener("click", () => adjustMoney(10));
element6.addEventListener("click", () => adjustMoney(-1));
.group { display: flex; gap: 0.5rem; }
<h2>HP</h2>
<div class="group">
<button id="odejmij-zycie">-</button>
<div id="suma-zycia">0</div>
<button id="dodaj-zycie">+</button>
</div>
<h2>Money</h2>
<div class="group">
<button id="odejmij-pieniadze">-</button>
<div id="suma-pieniedzy">0</div>
<button id="dodaj-pieniadze">+</button>
</div>

HTML Input Form to a Javascript Variable

I'm trying to implement an HTML form input, of which will take the numerical value and convert it into a variable in Javascript. This will then be used with chartjs to plot an graph.
I have the graph fully functioning if I input the variable separately, as used in the code below. I have been trying to use a function to take the value from the HTML form.
var force = 10
var numberOfPointLoads = 1
var pointLoadLocation = 5
var beamLength = 10
var supportCondition = "simplySupported"
var split = beamLength //No. of Finite Elements
var splitArrayYAxis = Array.from({
length: (split + 1)
}, (x, i) => i);
var yAxis = splitArrayYAxis.map(x => (x * (beamLength / split)));
yAxis.push(pointLoadLocation)
yAxis.push(pointLoadLocation)
yAxis.sort(function(a, b) {
return a - b
});
var splitArrayXAxis = Array.from({
length: (split + 1)
}, (x, i) => i);
var xAxisEnd = splitArrayYAxis.map(x => (x * (beamLength / split)));
xAxisEnd.push(pointLoadLocation)
xAxisEnd.sort(function(a, b) {
return a - b
});
var xAxisStart = xAxisEnd.splice(0, (xAxisEnd.indexOf(pointLoadLocation) + 1));
xAxisEnd.unshift(pointLoadLocation);
var shearForce = force / 2
var xAxisStart = xAxisStart.map(x => (shearForce))
var xAxisEnd = xAxisEnd.map(x => (-shearForce))
var xAxis = xAxisStart.concat(xAxisEnd)
var data = yAxis.map((v, i) => ({
x: v,
y: xAxis[i]
}));
//chart is below this
new Chart(document.getElementById("shearPointLoad"), {
type: "scatter",
data: {
datasets: [{
label: "MyScatter",
lineTension: 0,
data: data
}]
},
options: {
stacked: false,
bezierCurve: false,
title: {
display: true,
text: 'Plot of the Scatter'
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="shearPointLoad" width="400" height="250"></canvas> Force Input <input type="text" id="userInput"></input>
<button id="submitter">Submit</button>
<div id="output"></div>
The variable will be equal to the value of the HTML and will be reassigned when updated.
Thanks for any help.
EDIT
let someInput = document.getElementById('someInput')
function onButtonClick() {
let someVariable = parseFloat(someInput.value);
console.info(someVariable);
}
var force = "someVariable"
var numberOfPointLoads = 1
var pointLoadLocation = 5
var beamLength = 10
var supportCondition = "simplySupported"
var split = beamLength //No. of Finite Elements
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="shearPointLoad" width="400" height="250"></canvas>
<input id="someInput" type="number" <input/>
<button onclick="onButtonClick()">Click me</button>
Add onclick event to the button and define a function plotchart():
<button id="submitter" onclick="plotchart()">Submit</button>
Now, to read the input value in the function:
var data = document.getElementById("userInput").value;
Now, wrap all you chart plotting code inside plotchart() function.
You need to use the button event onclick, so every time you click it, you can then grab the input's value using a reference to the element. Like the following snippet:
let someInput = document.getElementById('someInput')
function onButtonClick() {
let someVariable = parseFloat(someInput.value);
console.info(someVariable);
}
<input id="someInput" type="number" />
<button onclick="onButtonClick()">Click me</button>
After this, you may use someVariable for anything you need.
Notes:
Use a type="number" input for better UX (so users can't input text or some other characters)
Consider resetting the input value after clicking the button.

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

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;
}

Kendo Chart with simple dynamic grid

I have a chart with date and count, avg, min, max functions. When I click functions I can get all values of my chart.
I just want to show a simple grid near my chart. I just want to show my categories name and their values. I have been trying for hours but I couldn't do that.
I can show my categories name with this code:
$("#ce").html(series[3].name);
And I want to show its value near it.
But I can't. Thanks for your help.
Here is an example of what I mean with JavaScript functions:
Telerik Kendo chart with date functions
Here is my code:
<td>
<div align="center" id="aa">
#(Html.Kendo().Chart(Model)
.Name("chartMesleki258")
.Title(title => title
.Text("aa)")
.Position(ChartTitlePosition.Top))
.Legend(legend => legend
.Visible(true)
.Position(ChartLegendPosition.Top))
.Series(series =>
{
series
.Column(model => model.aa, categoryExpression: model => model.EvrakTarih).Name("eee Dosyalar")
.Aggregate(ChartSeriesAggregate.Count);
series
.Column(model => model.aa, categoryExpression: model => model.EvrakTarih).Name("eee Dosyalar")
.Aggregate(ChartSeriesAggregate.Count);
series
.Column(model => model.aa, categoryExpression: model => model.EvrakTarih).Name("Kapsam Disi Dosyalar")
.Aggregate(ChartSeriesAggregate.Count);
})
.CategoryAxis(axis => axis
.Date()
.BaseUnit(ChartAxisBaseUnit.Months)
.MajorGridLines(lines => lines.Visible(false)))
.Tooltip(tooltip => tooltip
.Visible(true)
.Template("#= series.name #: #= value #"))
)
</div>
</td>
<script>
$(document).ready(function () {
$(".configuration").bind("change", refresh);
});
function refresh() {
var chart = $("#chartMesleki258").data("kendoChart"),
series = chart.options.series,
type = $("input[name=seriesType]:checked").val(),
stack = $("#stack").prop("checked");
for (var i = 0, length = series.length; i < length; i++) {
series[i].stack = stack;
series[i].type = type;
};
chart.refresh();
}
</script>
<script type="text/javascript">
$(".configuration").bind("change", refresh);
function refresh() {
var chart = $("#chartMesleki258").data("kendoChart"),
series = chart.options.series,
categoryAxis = chart.options.categoryAxis,
baseUnitInputs = $("input:radio[name=baseUnit]"),
aggregateInputs = $("input:radio[name=aggregate]");
for (var i = 0, length = series.length; i < length; i++) {
series[i].aggregate = aggregateInputs.filter(":checked").val();
}
categoryAxis.baseUnit = baseUnitInputs.filter(":checked").val();
chart.refresh();
}
</script>

Categories

Resources