Lynn
Lynn

Reputation: 23

How to open a Popup window which contains a graph written in javascript?

I am using Django to implement a website and I would like to add a button such that when someone clicks it, it would open a Popup window which contains a graph written in javascript. And since I am writing the website in Django, I need to call a function in views.py to get the updated data and then draw the graph based on that. I originally want to update the graph on one page but now I would like to open a popup window. Could someone help me on how to modify the code so that the button would Popup a smaller window which contains the graph I implemented? Thanks! Here is my code in main.html:

# I first have a button that could be clicked
<div class="col-lg-4">
 <p><button class="btn btn-primary" type="button" name="display_list" id="display_list">Display List</button></p>
</div>
# here is the script I used to open up a Popup window such that the returned result would be displayed on that separate window
<script>
    $(document).ready(function(){
      $("#display_list").click(function(){
        $.get("display_list/", function(ret){
            $('#result').bPopup(); #I think probably I did this wrong?
         });
      });
    });
</script>

And here is the code I used to draw the graph in a separate html file(show_result.html):

<div id="result">
<script> javascript that draws a graph on html webpage. I pass the updated variable from the corresponding function in views.py to here by calling render(). </script>
</div>

Here is my function in the views.py:

def display_list(request):
   #some function implementation to get the result and put it in context
   return render(request, "show_result.html",context)

And this is the code in my url file:

url(r'^display_list/$', views.display_list, name='display_list'),

Is it possible to Popup a div in html? And what should I do in my case?

Thanks a lot.

Upvotes: 1

Views: 2647

Answers (2)

Aakash
Aakash

Reputation: 1515

There can be two ways of performing the task that you want. Here are the methods.

Version 1 (The synchronous way)
Suppose you have a url say /x/ which opens main.html. So you can add whatever data, graph needs to the context on a GET call. Example:

def x(request):
    context = {}
    # Add data that is needed to draw the graph, in your context
    return render(request, "main.html",context)

Now you have the data that is needed to draw your graph, in your main.html's context. Now you can simply use a Bootstrap modal to draw your graph in a pop up.

<div class="col-lg-4">
    <p><button class="btn btn-primary" type="button" data-toggle="modal" data-target="#myModal"id="display_list">Display List</button></p>
</div>

<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
  <div class="modal-dialog">

    <!-- Modal content-->
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">&times;</button>
        <h4 class="modal-title">Modal Header</h4>
      </div>
      <div class="modal-body" id="modal-body">
        <p>Some text in the modal.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
      </div>
    </div>

  </div>
</div>

You don't need the click event listener on #display_list since Bootstrap handles that.

<script>
    // Put your graph logic here and use '#modal-body' to render the graph
</script>

Version 2 (The Async way)
In this case we have already opened the page on /x/ and we will get data from /display_list/ via an AJAX GET call.

def display_list(request):
    ''' Function to return data in json format to ajax call '''
    context = {}
    #Get all data required to draw the graph and put it in context

    return JsonResponse(context)

Since when you click the button you want to send AJAX request and then open the modal, you need to remove data-toggle="modal" data-target="#myModal" from the button to prevent it from opening. Change the button to:

<p><button class="btn btn-primary" type="button" id="display_list">Display List</button></p>

Now you can hit the url /display_list/ to get your data. In your main.html add the Bootstrap modal element as in version 1. Now add the following Javascript to main.html to get the data.

<script>
    $(document).ready(function(){
        $("#display_list").click(function(e){
            e.preventDefault();
            var modalBody = $("#modal-body");
            // AJAX call to get the data
            $.ajax({
                url: '/display_list/',
                type: 'GET',
                success: function(data, status, xhr) {
                    console.log(data);
                    // Add your graph logic here and use modalBody to draw on it
                }
            });

            //Now display the modal
            $("#myModal").modal('show');
        });
    });
</script>

NOTE
Remember to add Bootstrap's CSS and JS files.

<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

Example
So I will be going by version 1 here in the example. I am using the graph provided here Step 1: Your view x should look like this:

def x(request):
    context = {}
    links = [
        {'source': "Microsoft", 'target': "Amazon", 'type': "licensing"},
        {'source': "Microsoft", 'target': "HTC", 'type': "licensing"},
        {'source': "Samsung", 'target': "Apple", 'type': "suit"},
        {'source': "Motorola", 'target': "Apple", 'type': "suit"},
        {'source': "Nokia", 'target': "Apple", 'type': "resolved"},
        {'source': "HTC", 'target': "Apple", 'type': "suit"},
        {'source': "Kodak", 'target': "Apple", 'type': "suit"},
        {'source': "Microsoft", 'target': "Barnes & Noble", 'type': "suit"},
        {'source': "Microsoft", 'target': "Foxconn", 'type': "suit"},
        {'source': "Oracle", 'target': "Google", 'type': "suit"},
        {'source': "Apple", 'target': "HTC", 'type': "suit"},
        {'source': "Microsoft", 'target': "Inventec", 'type': "suit"},
        {'source': "Samsung", 'target': "Kodak", 'type': "resolved"},
        {'source': "LG", 'target': "Kodak", 'type': "resolved"},
        {'source': "RIM", 'target': "Kodak", 'type': "suit"},
        {'source': "Sony", 'target': "LG", 'type': "suit"},
        {'source': "Kodak", 'target': "LG", 'type': "resolved"},
        {'source': "Apple", 'target': "Nokia", 'type': "resolved"},
        {'source': "Qualcomm", 'target': "Nokia", 'type': "resolved"},
        {'source': "Apple", 'target': "Motorola", 'type': "suit"},
        {'source': "Microsoft", 'target': "Motorola", 'type': "suit"},
        {'source': "Motorola", 'target': "Microsoft", 'type': "suit"},
        {'source': "Huawei", 'target': "ZTE", 'type': "suit"},
        {'source': "Ericsson", 'target': "ZTE", 'type': "suit"},
        {'source': "Kodak", 'target': "Samsung", 'type': "resolved"},
        {'source': "Apple", 'target': "Samsung", 'type': "suit"},
        {'source': "Kodak", 'target': "RIM", 'type': "suit"},
        {'source': "Nokia", 'target': "Qualcomm", 'type': "suit"}
    ]
    context['links'] = links
    return render(request, 'main.html', context)

Step 2: In your main.html add the following to your <head> tag.

<script   src="https://code.jquery.com/jquery-2.2.4.min.js"   integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="   crossorigin="anonymous"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>    
    .link {
        fill: none;
        stroke: #666;
        stroke-width: 1.5px;
    }

    #licensing {
        fill: green;
    }

    .link.licensing {
        stroke: green;
    }

    .link.resolved {
        stroke-dasharray: 0,2 1;
    }

    circle {
        fill: #ccc;
        stroke: #333;
        stroke-width: 1.5px;
    }

    text {
        font: 10px sans-serif;
        pointer-events: none;
        text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
    }
    .modal-dialog {
        width: 63% !important;
    }
</style>

Step 3: This will be your <body> tag in main.html, in this you will need to have a global var links = {{ links|safe }} variable. We cant shift the script to a separate file since django template tag wont work there.

<body>
    <div class="col-lg-4">
        <p><button class="btn btn-primary" type="button" data-toggle="modal" data-target="#myModal" id="display_list">Display List</button></p>
    </div>

    <!-- Modal -->
    <div id="myModal" class="modal fade" role="dialog">
      <div class="modal-dialog">

        <!-- Modal content-->
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal">&times;</button>
            <h4 class="modal-title">Modal Header</h4>
          </div>
          <div class="modal-body" id="modal-body">

          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
          </div>
        </div>

      </div>
    </div>

    <script>

        var links = {{ links|safe}};
        var nodes = {};

        // Use elliptical arc path segments to doubly-encode directionality.
        function tick() {
          path.attr("d", linkArc);
          circle.attr("transform", transform);
          text.attr("transform", transform);
        }

        function linkArc(d) {
          var dx = d.target.x - d.source.x,
              dy = d.target.y - d.source.y,
              dr = Math.sqrt(dx * dx + dy * dy);
          return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
        }

        function transform(d) {
          return "translate(" + d.x + "," + d.y + ")";
        }

        // Compute the distinct nodes from the links.
        links.forEach(function(link) {
          link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
          link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
        });

        var width = 860,
            height = 500;

        var force = d3.layout.force()
            .nodes(d3.values(nodes))
            .links(links)
            .size([width, height])
            .linkDistance(60)
            .charge(-300)
            .on("tick", tick)
            .start();

        var svg = d3.select("#modal-body").append("svg")
            .attr("width", width)
            .attr("height", height);
            // Per-type markers, as they don't inherit styles.
            svg.append("defs").selectAll("marker")
            .data(["suit", "licensing", "resolved"])
          .enter().append("marker")
            .attr("id", function(d) { return d; })
            .attr("viewBox", "0 -5 10 10")
            .attr("refX", 15)
            .attr("refY", -1.5)
            .attr("markerWidth", 6)
            .attr("markerHeight", 6)
            .attr("orient", "auto")
          .append("path")
            .attr("d", "M0,-5L10,0L0,5");

        var path = svg.append("g").selectAll("path")
            .data(force.links())
          .enter().append("path")
            .attr("class", function(d) { return "link " + d.type; })
            .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });

        var circle = svg.append("g").selectAll("circle")
            .data(force.nodes())
          .enter().append("circle")
            .attr("r", 6)
            .call(force.drag);

        var text = svg.append("g").selectAll("text")
            .data(force.nodes())
          .enter().append("text")
            .attr("x", 8)
            .attr("y", ".31em")
            .text(function(d) { return d.name; });


    </script>
</body>

Thats it you are ready to go. Look carefully you don' require to add a click event to #display_list as Bootstrap handles all that.

Here's a JSBin demo

Upvotes: 2

jsanchezs
jsanchezs

Reputation: 2070

It's completely possible using bootstrap modals, here's documentation about it : http://www.w3schools.com/bootstrap/bootstrap_modal.asp

And a sample code :

<div class="modal fade" id="id_you_want_for_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="myModalLabel"> Title you want </h4>
      </div>
           <div class="modal-body">
               <!-- Your Graph here  -->
          </div>
    </div>
  </div>
</div>  

Do not forget to include the bootstrap js and css files in your project :

http://getbootstrap.com/getting-started/

http://www.w3schools.com/bootstrap/bootstrap_get_started.asp

Hope it helps !

Upvotes: 0

Related Questions