I am trying to create flowing stacked area chart using d3.js. I have the graph working with a specific range. I am hitting the service every 10ms and getting all data and then triggering an event to start the graph. However my graph works only works for 30mins after that I am trying to reset the interval. When I am trying to do that it there is a jerk in the graph and somehow it breaks. I am not sure if I am doing it the right way. Here is code to look at.
var numbers = [];
var values = [];
var flag = false;
var fd;
var td;
//Calling the dates service
d3.json('/api/dates', function(error,data) {
var dates = data;
if(data != null){
fd = new Date(data.start);
td = new Date(data.end);
var cnt = 0;
var startGraph = function(){
if (fd > td) {
console.log(" start Date is greater than end Date");
clearInterval(interval);
flag = true;
$('.wrapper').trigger('newPoint');
return;
}
var fdt = fd.toISOString();
var tdt = new Date(fd.setMinutes(fd.getMinutes() + 30)).toISOString();
//Calling service to get the values for stacked area chart
d3.json("/api/service?start=" +fdt+ "&end=" +tdt, function(error,result) {
if(result != null){
numbers = numbers.concat(flightInfo.numbers);
values[values.length] = flightInfo.values;
}
});
cnt++;
}
function pushPoint(){
var cnt=0;
var interval = setInterval(function(){
if(cnt!=values.length)
{
tick(values[cnt]);
cnt++;}
else
clearInterval(interval);
},400);
}
//Calling the Processing Dates API to pull the data for area chart
var interval = setInterval(startGraph,10);
}
});
$(document).ready(function () {
stackGraph(); // this is another js file
var cnt=0;
//Pushing new point
$('.wrapper').on('newPoint', function(){
if(flag){
if(cnt!=values.length){
tick(values[cnt]);
cnt++;
}
}
});
});
Is there actually a line break on the line with your return statement here?
$('.background').trigger('newPoint');
return //is there actually a line break here?
setTimeout(startGraph,10);
If so, you aren't going to execute the next line.
Why doesn't a Javascript return statement work when the return value is on a new line?
Related
I decided to build a high/low game in javascript and am running into an issue where the numbers displayed are ahead of what the variables have stored or the exact opposite. I can't seem to get them to match.
EDIT: I figured it out, the code ran before ajax was done causing an offset.
It helps me more when I find answers with the old code to compare with the new so I'll leave the broken code. Updated with working code at the end.
Page that helped me figure out a fix:
Wait for AJAX before continuing through separate function
Original JavaScript:
var y = "0";
var z = "0";
var output_div = document.getElementById("outcome");
var last_ = document.getElementById("val");
var cardVal;
function higher(x) {
var new_ = last_.innerHTML; //getting new value
y = last_.getAttribute("data-old"); //getting old value
console.log("data_old " + y);
z = ajx(); //calling function return the value from which need to compare
console.log("data_new " + z);
if (x === 1) {
if (z > y) {
output_div.innerHTML = "Winner!";
} else {
output_div.innerHTML = "Loser!";
}
} else {
if (z < y) {
output_div.innerHTML = "Winner!";
} else {
output_div.innerHTML = "Loser!";
}
}
last_.setAttribute("data-old", new_); //setting old value with current value of div
}
function ajx() {
$.ajax({
url: "./getfacecard.php",
success: function(response) {
var result = $.parseJSON(response);
var img = result[0];
cardVal = result[1];
document.getElementById(\'card\').src = img;
document.getElementById(\'val\').innerHTML = cardVal;
}
});
return cardVal; // return current card value in calling function
}
Updated Working JavaScript:
var lastVal = document.getElementById("lastVal"); //Last played cars value
var wl = document.getElementById("outcome"); //Shows win or lose
var newVal = document.getElementById("currentVal"); //Current face up card
var iSrc = document.getElementById("card"); //Card img
var lVal; //Last cards value from post
var iLink; //Image link from post
var nVal; //Gets new html to be sent to post.
function start(x){
// console.log("Start:");
ajx(function(){ //Runs ajax before continuing
iSrc.src = iLink; //Set new card image src
newVal.innerHTML = nVal; //Sets Current card value in div
lastVal.innerHTML = lVal; //Sets Last card value in div
// console.log("-slgn"); //Consoles to track code launch order.
// console.log("-Last Value: "+lVal);
// console.log("-Current Value: "+nVal);
// console.log("-Link: "+iLink);
// console.log(x);
if(x===1){ //If clicked higher
if(nVal>lVal){ //If new card is higher than old card
wl.innerHTML = "Winner!";
}else{
wl.innerHTML = "Loser!"
}
}
if(x===2){
if(nVal<lVal){ //If new card is lower than old card
wl.innerHTML = "Winner!";
}else{
wl.innerHTML = "Loser!"
}
}
});
}
function ajx(callback) {
$.ajax({
type: "POST",
data: {data:newVal.innerHTML}, //Post new card value to be returned as last card.
url: "./getfacecard.php",
success: function(response) {
var result = $.parseJSON(response);
iLink = result[0]; //img
lVal = result[2]; //Last card
nVal = result[1]; //New Card
// console.log("ajax");
callback(); //Go back and the code
}
});
}
You can use custom attribute in your div to save your current value as old value and vice versa so only one div required here i.e: Your div look like below :
<div data-old="0" id="val">0</div>
And js code will look like below:
var y = "0";
var z = "0";
var output_div = document.getElementById("outcome");
var last_ = document.getElementById("val");
function higher(x) {
var new_ = last_.innerHTML; //getting new value
y = last_.getAttribute("data-old"); //getting old value
console.log("data_old " + y);
z = ajx(); //calling function return the value from which need to compare
console.log("data_new " + z);
if (x === 1) {
if (z > y) {
output_div.innerHTML = "Winner!";
} else {
output_div.innerHTML = "Loser!";
}
} else {
if (z < y) {
output_div.innerHTML = "Winner!";
} else {
output_div.innerHTML = "Loser!";
}
}
last_.setAttribute("data-old", new_); //setting old value with current value of div
}
function ajx() {
$.ajax({
url: "./getfacecard.php",
success: function(response) {
var result = $.parseJSON(response);
var img = result[0];
var cardVal = result[1];
document.getElementById('card').src = img;
document.getElementById('val').innerHTML = cardVal;
}
});
return cardVal; // return current card value in calling function
}
In above js code what i done is after ajax call finishes execution it will return cardVal which will get pass in variable z and then we will compare it with y i.e : old value and print required output.Also, i have return value from ajax called because when you do document.getElementById(\'val\').innerHTML = cardVal; still this value is not available with us in our function higher so to overcome this i have return that value to your calling function.
(This code is already tested and working as excepted )
I am trying to parse an GoJS diagram, user can drag different categories from a plate, circle node, rectangle node, triangle. and he can interconnect them in in one direction until reaching the end.
the required function is to parse the graph and give a list of possible paths according the user dependency graph. sample graph is shown here
my function is something like this code:
function collectPaths(y, x) {
var stack = new go.List(go.node);
var coll = new go.List(go.List);
lock = false;
function find(y, x) {
console.log(y.data.name);
y.findNodesInto().each(function (n) {
console.log(y.data.name + " ●▬● " + n.data.name);
if ((n.data.key == x.data.key) && !(lock)) { // success
console.log(n.data.name);
var path = stack.copy();
path.reverse();
coll.add(path);
} else if((n.data.key !=x.data.key) && lock){
// stack.add(n);
console.log(n.data.name);
if (n.data.category === "triangle") {
pp = pp.findNodesInto();
var it = pp.iterator;
var m = new go.Map(go.node, "number");
lock = true;
while (it.next()) {
m.pop(it.value,it.value);
stack.add(it.value);
console.log(it.value.data.name);
find(it.value, x);
}
var tempList=go.list(go.node);
tempList.each(function (pn) {
pn = tempList.pop();
if (!"undefined") {
stack.add(parent);
find(parent, x);
// stack.add(pn);
console.log(pn.data.name);
} else {
pn = tempList.pop();
find(pn, x);
}
});
} else {
console.log(n.data.name);
stack.add(n);
find(n, x);
stack.removeAt(stack.count - 1);
}
}
lock = false;
});
} // end of full stack collection
find(y, x);
return coll;
}
but the function doesn't give the required output.
expected output like this: for the figure attached as follows:
N30 – N40 – N10
N1 -N2-N3-N4-N10
N5-N6-N9-N10
N5-N10
N7-N8-N10
N7-N8-N11-N10
What I can do ?
The sample https://gojs.net/latest/samples/distances.html demonstrates how to find all paths between any pair of nodes. You want to use the collectAllPaths function -- you can delete the functions involved with creating a random graph or with finding distances between nodes or with helping the user select the start and end nodes interactively.
I'm using fabricjs and want to render the text every time a value is updated.
But when I do this, the new text overlaps the old. I tried to clear the object but didn't find any way to do so.
Below is the code snippet to describe what I doing:
//console.log('topp'+ rect.getTop());
rect.on('moving', function() {
var rectTop = rect.getTop();
var upCounter = 0;
var downCounter = 0;
var text40;
var canvas_objects = canvasForRect._objects;
// console.log('topp'+ rect.getTop());
// READ STRING FROM LOCAL STORAGE
var retrievedObject = localStorage.getItem('heatMapClickData');
// CONVERT STRING TO REGULAR JS OBJECT
var text40;
var last = canvas_objects[canvas_objects.length - 1];
var parsedObject = JSON.parse(retrievedObject);
$.each(parsedObject, function(index, item) {
if (rectTop >= item['pos_y']) {
upCounter += 1;
} else {
downCounter += 1;
}
text40 = new fabric.Text("Total clicks above line" + upCounter, {
fontSize: 40
});
});
// var obj = canvasForRect.getActiveObject();
// console.log(obj);
text40.set({
text: "Total clicks above line" + upCounter
});
canvasForRect.add(text40);
// canvas.renderAll();
});
How do I re-render the text every time upCounter is updated?
I am trying to create a stack area graph from the values I get from api's.
My first api gives me a range of dates. Eg: June 1 - June 7.
My second api gives me values need for the graph. The data looks like this
My idea is to call the api and push the count values to function every time to a function. But somehow I could not make that possible so I am calling api once for every 100 ms and grabbing all the data and triggering the graph. Now when I want to call the second api after one iteration is complete the call interrupts the graph. Please help me fix this.
d3.json('/service/dates', function(error, dates) {
var dran = dates;
if (dates != null) {
sDt = new Date(dates.st);
eDt = new Date(dates.et);
var i = 0;
var start = function() {
if (sDt > eDt) {
clearInterval(interval);
$('.wrapper').trigger('newPoint');
return;
}
var sDate = sDt.toISOString();
var eDate = new Date(sDt.setMinutes(sDt.getMinutes() + 30)).toISOString();
//Calling the api for graph values
d3.json("/service/dat?s=" + sDate + "&e=" + eDate, function(error, results) {
if (results != null) {
numbers = numbers.push(results.numbers);
values = values.push(results.values);
}
});
i++;
}
var interval = setInterval(start, 100);
}
});
}
Put the entire API call inside a named function. Then call that from the start() function to restart everything.
function doAPILoop() {
d3.json('/service/dates', function(error, dates) {
var dran = dates;
if (dates != null) {
sDt = new Date(dates.st);
eDt = new Date(dates.et);
var i = 0;
var start = function() {
if (sDt > eDt) {
clearInterval(interval);
$('.wrapper').trigger('newPoint');
doAPILoop();
return;
}
var sDate = sDt.toISOString();
var eDate = new Date(sDt.setMinutes(sDt.getMinutes() + 30)).toISOString();
//Calling the api for graph values
d3.json("/service/dat?s=" + sDate + "&e=" + eDate, function(error, results) {
if (results != null) {
numbers = numbers.concat(results.numbers);
values[values.length] = results.values;
}
});
i++;
}
var interval = setInterval(start, 10);
}
});
}
doAPILoop();
I'm trying to create a "bar" that is highlight-able and will return a value which contains the number of div boxes that were highlighted. For example, when I highlight 5 divs, it should return 5. When I continue on, and highlight another 6 boxes, it should return 6. All of the highlighted results should be in an array var x = ["5", "6",...];
Here's a fiddle https://jsfiddle.net/aepxqztL/3/
$(document).ready(function() {
var $range = $('.range-bar').mousedown(function() {
$(this).toggleClass('highlight');
var flag = $(this).hasClass('highlight')
$range.on('mouseenter.highlight', function() {
$(this).toggleClass('highlight', flag);
});
});
$(document).mouseup(function() {
$('.range-bar').off('mouseenter')
})
});
Any help will be appreciated.
Here is an example using jQuery.each to calculate the highlighted divs upon mousedown event
function calculateArray(){
var x = [];
$("div.range-bar").each(function( index, value ) {
if($(this).hasClass("highlight"))
x.push(index);
});
return x;
}
var x = [];
$(document).ready(function() {
var $range = $('.range-bar').mousedown(function() {
$(this).toggleClass('highlight');
var flag = $(this).hasClass('highlight')
$range.on('mouseenter.highlight', function() {
$(this).toggleClass('highlight', flag);
});
x = calculateArray();
console.log(x);
});
$(document).mouseup(function() {
$('.range-bar').off('mouseenter')
})
});
See working demo: https://jsfiddle.net/aepxqztL/7/
It looks like you need to set 2 global vars (a range counter rangeVal and a data array dataSet) and then increment the rangeVal on mousedown on each box and then add it to the dataSet on mouseup and then reset rangeVal.
Eg.
var dataSet = []; //data array
var rangeVal = 1; //range counter
$(document).ready(function() {
var $range = $('.range-bar').mousedown(function() {
$(this).toggleClass('highlight');
var flag = $(this).hasClass('highlight')
$range.on('mouseenter.highlight', function() {
$(this).toggleClass('highlight', flag);
rangeVal++; //Increment on mousedown mouseenter in box
});
});
$('.range-bar').mouseup(function() {
$('.range-bar').off('mouseenter')
dataSet.push(rangeVal); //add range counter to data array
rangeVal = 1; //reset range counter
$('.results p').text(dataSet.join()); //display data array in results div
})
});
See this fiddle here: https://jsfiddle.net/pavkr/0vftp5ja/1/
The question is still a little vague but I think this is what you're looking for.
EDIT:
https://jsfiddle.net/pavkr/0vftp5ja/2/
Modified so that it saves the Start and End value as well as the Range value.