8

I want to update my canvas on every AJAX request if new user is found or there is new connection of existing users.

I have users and connections between them:

 var data=[
           {
              "Id": 38,
               "Connections":[39,40],
               "Name":"ABc"
          },
           {
              "Id": 39,
               "Connections":[40],
               "Name":"pqr"
           },
           {
               "Id": 40,
               "Connections":[],
               "Name":"lmn"
           }]

In the above example user with Id:38 is connected to user 39 and 40 and user 39 is connected to user 40 and user 40 is already connected to user 39 and user 38 so user 40 Connection array is blank.

I have one web service which I will fire every 1-2 seconds to display newly joined users on this page and new connection between existing users which I have stored in my table and this web service will fetch all users along with their connections.

So at first my page will load but after then my page will not refresh and new users should be displayed and new connections should be connected with AJAX call to my web service.

But with ajax request everything gets messed up. This is a JSBin I have created.

Output I am getting:

enter image description here

I have just 4 users and 3 connections as you can see in my JSBin output then it should be just 4 rectangles and I am not adding more users but still getting this messy output.

Source code reference: Reference Fiddle

I am trying to get the output as shown in above fiddle but not getting.

Expected output: 4 rectangles with animation

Updated Js bin Demo: Updated JSBin

With above updated JSBin I am getting this output but they are not moving (animation is not working):

Updated Output

halfer
  • 18,701
  • 13
  • 79
  • 158
  • 1
    Are you clearing the canvas between draws? That output looks like what you'd get from the rectangles persisting between each update. – DBS May 13 '16 at 16:10
  • @DBS can you please elaborate – Learning-Overthinker-Confused May 13 '16 at 17:16
  • 1
    When you draw something on a canvas, the previous image remains visible unless you specifically clear the canvas yourself. So drawing one of your ID's multiple times may appear as multiple squares. Think of it as adding new squares to the same image, instead of creating a new image. Try clearing it once you get the ajax request, before you draw any new squares. – DBS May 13 '16 at 17:47
  • 1
    How to clear a canvas: http://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing – DBS May 13 '16 at 17:48
  • @DBS ok I will surely try but still if you can post some codes then it would really help me alot because I have started working on canvas from tomorrow – Learning-Overthinker-Confused May 13 '16 at 18:07
  • @DBS you can try my js bin code and if you want I can give you my web service for data – Learning-Overthinker-Confused May 13 '16 at 18:08

2 Answers2

4

The boxes aren't moving because the code for moving them is never called.

If you move the part animating the boxes from updateUsers() to your main animation loop they will animate.

Move the section from this part:

function updateUsers() {
  fetchData();

  // this part ------------------------------------------------------
  $.each(users, function(index, user) {
    if (user.x <= 0) user.dir.x = 1;
    if (user.x + user.width > canvas.width) user.dir.x = -1;
    if (user.y <= 0) user.dir.y = 1;
    if (user.y + user.height > canvas.height) user.dir.y = -1;

    user.x += user.dir.x;
    user.y += user.dir.y;
  });
  // to here --------------------------------------------------------

  //window.setTimeout(updateUsers, 1000 / 60);
  window.setTimeout(updateUsers, 9000);
}

to here:

function drawUsers() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  $.each(users, function(index, user) {
    ctx.beginPath();
    ctx.rect(user.x, user.y, user.width, user.height);
    ctx.strokeStyle = 'red';
    ctx.stroke();

    if (user.connections != null) {
      user.connections.forEach(function(id) {
        const other = users.find(user => user.id === id);

        ctx.beginPath();
        ctx.moveTo(user.x + (user.width / 2), user.y + (user.height / 2));
        ctx.lineTo(other.x + (other.width / 2), other.y + (other.height / 2));
        ctx.strokeStyle = 'black';
        ctx.stroke();
      });
    }
  });

  // animate here
  $.each(users, function(index, user) {
    if (user.x <= 0) user.dir.x = 1;
    if (user.x + user.width > canvas.width) user.dir.x = -1;
    if (user.y <= 0) user.dir.y = 1;
    if (user.y + user.height > canvas.height) user.dir.y = -1;

    user.x += user.dir.x;
    user.y += user.dir.y;
  });
  window.requestAnimationFrame(drawUsers);
}

Since we don't have access to the web service you're using, and assuming the data is correctly returned, I had to uncomment the predefined data to make a working demo:

Updated jsbin

  • ok i have tested your solution but when creating new connections it is creating others duplicate rectangles.If you want i can give you my web service url so that you can see actual problem – Learning-Overthinker-Confused May 31 '16 at 10:40
  • 1
    @Learning it would help, or a couple of sets with some simulated new data if you're uncomfortable sharing it here. –  May 31 '16 at 10:45
  • 1
    Actually when i have already 1 connection record in my database and when i run it then it works fine but when i create new connections in database and my ajax request fetches this new connections that is when the problem get occured. – Learning-Overthinker-Confused May 31 '16 at 10:49
  • 1
    @Learning It's a bit unclear, I mean, each XHR request is a new connection. What are you using on server side? And does the user id somehow change depending on connection (assuming web sockets) ? You could try to replace the entire dataset when a new connection is made, or? –  May 31 '16 at 10:55
1

I worked from your Source Code Reference Fiddle, which worked pretty ok to me.

Added a couple of things:

First of a seperate function to add a user to the users array. This way, users can easily be added after a successful webservice call.

Second, addded a couple of helper functions to get random positions and directions.

function addUser(user) {
    users.push({
    id: user.UserId,
    connections: user.Connections,
    width: 80,
    height: 80,
    x: getRandomX(),
    y: getRandomY(),
    dir: {
        x: getDir(),
        y: getDir()
    }
  });
}

// the success callback from your webservice
// guess this receives a `user` object with Id and Connections
// for the test we use `getRandomConnections` 
function getDataFromWebService() {
  let newUser = { "UserId": Date.now(), "Connections": getRandomConnections() };
  addUser(newUser);
}

Fiddle

When you connect your webservice, you can ditch the getRandomConnections function and reference. In your webservice success callback, make sure you have an object in the format:

{ UserId: 1337, Connections: [1, 2] }

Pass that object to the addUser function.

Pimmol
  • 1,755
  • 1
  • 6
  • 13
  • if you have web service url then what should be removed from your code and what to use?? – Learning-Overthinker-Confused May 31 '16 at 11:17
  • can i ask you for some suggestions?? – Learning-Overthinker-Confused May 31 '16 at 11:35
  • Sure you can [15 chars] – Pimmol May 31 '16 at 11:39
  • I have 2 tables i.e 1 is users and 2nd is userconnections.now in users only users data will be stored and in usersconnection table i have 2 fields ie id from and to and in this 2 fields i would have values like 1 and 2 and this 1 and 2 are nothing but userid from users tables and this from and to shows that this 2 users are connected.now i am thinking to seperate 2 calls that is in 1 call i would be fetching new users every 2-3 seconds and in 2nd call i would be fetching new connections from this userconnections table to draw line between two users.What you suggest? – Learning-Overthinker-Confused May 31 '16 at 11:56
  • I suggest 1 call to get both users and connections and return that. The less calls the better (performance wise). Also, if you return everything at once you only have to perform 1 operation in JS instead of 2 – Pimmol May 31 '16 at 12:00