简体   繁体   中英

javascript function not visible? does not get called a second time

This may be a pretty newbie question so bear with me. I am tinkering a little with Ruby on Rails 4, Javascript and Raphael. I'm using Backbone too. On my root page I got two buttons, one which renders some stuff with Raphael and another one which is supposed to do the same after changing a related parameter.

In my application.js I got the following:

var app = {};
$(document).ready(function() {
  app.paper = Raphael("canvas", 1000,700); // canvas: html div
  ...
  app.Room = Backbone.Model.extend({
    ...
  }
  app.RoomList = Backbone.Collection.extend({
    model: app.Room
  });
  ...
  app.drawRoom = function(room, x, y, z) {
    ...
  }
  ...
});

Upon clicking the first button, a .js.erb view kicks in and calls the following:

// retrieve data, stuff it into app.roomList, then this:
app.drawRoom(app.roomList.first(), 500, 300, 0);

This works as expected and renders a few circles and stuff. There's something more going behind the scenes (the rooms data is retrieved as a json from a different project's CDO server via RabbitMQ, but it's totally unrelated). Now, when I click the second button, I'm doing the following:

app.paper.clear();
app.drawRoom(app.roomList.first(), 800, 300, 1);

As you can see, my intention is to clean the canvas and redraw everything with different parameters. The new parameters are OK, and I've checked that the following works when pressing the second button, effectivaly leaving the canvas clean except for a lonely circle:

app.paper.clear();
app.paper.circle(222, 333, 15);

So I'm pretty certain it must be something related to my ignorance of javascript. I am also positive that the second call to app.drawRoom() is not executed, I tested it with Firebug. Perhaps some visibility issue? Thanks in advance!! Edit: The HTML for the buttons:

= form_tag( show_rooms_url, remote: true) do
  = submit_tag "show rooms"
= form_tag( up_level_url, remote: true) do
  = submit_tag "+1"

Which with routes.rb they are linked to 2 separate controller's methods:

def show_rooms
    conn = Bunny.new(:automatically_recover => false)
    conn.start

    ch = conn.create_channel

    client   = ApplicationHelper::RPCClient.new(ch, "rpc_queue")
    response = client.call("list_rooms")
    ch.close
    conn.close
    respond_to do |format|
        format.js { render partial: "show_rooms", locals: { response: response } }
    end
end

def up_level
    respond_to do |format|
        format.js { render partial: "up_level" }
    end
end

Then the views cointain the following calls (the same, actually, just different parameters):

app.drawRoom(app.roomList.first(), 500, 300, 0);

The generated HTML for the buttons is:

<form method="post" data-remote="true" accept-charset="UTF-8" action="http://localhost:3000/show_rooms">
  <input type="hidden" value="✓" name="utf8">
  <input type="submit" value="show rooms" name="commit">

and:

<form method="post" data-remote="true" accept-charset="UTF-8" action="http://localhost:3000/up_level">
  <input type="hidden" value="✓" name="utf8">
  <input type="submit" value="+1" name="commit">

Also, the drawRoom method:

$(document).ready(function(){
....
app.drawRoom = function(room, x, y, z) {
    if (room.get('drawn') == false) {
        room.set('drawn', true);
        if (app.level === z) {
            c = app.paper.circle(x, y, 15);
            c.attr("fill", "red");
        }

        if (room.get('n') !== "") {
            if (app.level === z) {
                app.paper.path(['M', x - 10, y - 10, 'Q', x - 20, y - 25, x - 10, y - 40]);
            }
            app.drawRoom(app.roomList.where({ id: room.get('n') })[0], x, y - 50, z);
        }
        if (room.get('e') !== "") {
            if (app.level === z) {
                app.paper.path(['M', x + 10, y - 10, 'Q', x + 25, y - 20, x + 40, y - 10]);
            }
            app.drawRoom(app.roomList.where({ id: room.get('e') })[0], x + 50, y, z);
        }
        if (room.get('s') !== "") {
            if (app.level === z) {
                app.paper.path(['M', x + 10, y + 10, 'Q', x + 20, y + 25, x + 10, y + 40]);
            }
            app.drawRoom(app.roomList.where({ id: room.get('s') })[0], x, y + 50, z);
        }
        if (room.get('w') !== "") {
            if (app.level === z) {
                app.paper.path(['M', x - 10, y + 10, 'Q', x - 25, y + 20, x - 40, y + 10]);
            }
            app.drawRoom(app.roomList.where({ id: room.get('w') })[0], x - 50, y, z);

        }
        if (room.get('u') !== "") {
            app.drawRoom(app.roomList.where({ id: room.get('u') })[0], x, y, z + 1);
        }
        if (room.get('d') !== "") {
            app.drawRoom(app.roomList.where({ id: room.get('d') })[0], x, y, z - 1);
        }
    }
}
});

Your second attempt at drawing anything is failing because the drawn variable on your Backbone model has been set to true. The below code specifies not to draw if that particular property is true:

if (room.get('drawn') == false) {
    room.set('drawn', true);

    // your room drawing code is here

}

If you'd like to keep your boolean drawn flag, put the if-statement in its entirety at the beginning of the method, like so:

if (room.get('drawn') == false) {
    room.set('drawn', true);
}

// your room drawing code should be here

To be clear, the whole drawRoom method should probably look like this:

app.drawRoom = function(room, x, y, z) {
    if (room.get('drawn') == false) {
        room.set('drawn', true);
    }
    if (app.level === z) {
        c = app.paper.circle(x, y, 15);
        c.attr("fill", "red");
    }
    if (room.get('n') !== "") {
        if (app.level === z) {
            app.paper.path(['M', x - 10, y - 10, 'Q', x - 20, y - 25, x - 10, y - 40]);
        }
        app.drawRoom(app.roomList.where({ id: room.get('n') })[0], x, y - 50, z);
    }
    if (room.get('e') !== "") {
        if (app.level === z) {
            app.paper.path(['M', x + 10, y - 10, 'Q', x + 25, y - 20, x + 40, y - 10]);
        }
        app.drawRoom(app.roomList.where({ id: room.get('e') })[0], x + 50, y, z);
    }
    if (room.get('s') !== "") {
        if (app.level === z) {
            app.paper.path(['M', x + 10, y + 10, 'Q', x + 20, y + 25, x + 10, y + 40]);
        }
        app.drawRoom(app.roomList.where({ id: room.get('s') })[0], x, y + 50, z);
    }
    if (room.get('w') !== "") {
        if (app.level === z) {
            app.paper.path(['M', x - 10, y + 10, 'Q', x - 25, y + 20, x - 40, y + 10]);
        }
        app.drawRoom(app.roomList.where({ id: room.get('w') })[0], x - 50, y, z);

    }
    if (room.get('u') !== "") {
        app.drawRoom(app.roomList.where({ id: room.get('u') })[0], x, y, z + 1);
    }
    if (room.get('d') !== "") {
        app.drawRoom(app.roomList.where({ id: room.get('d') })[0], x, y, z - 1);
    }
}

Also, have you attempted clearing the canvas with:

app.paper.clearRect( 0, 0, app.paper.width, app.paper.height )

I've found this to be the most effective way of doing so.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM