Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Monday, December 22, 2014

Bootstrap: Display a network graph within a tab page of a tab control

Recently I was working with bootstrap and needed to display a network graph within a bootstrap tab control. I decided to use vis.js which is easy to use for creating a graph network. Initially the problem looked simple as all that i need to do is to create tab control using bootstrap and create a graph network in one of its tab pages. Below is the original implementation:

<html>
<head>
<link href="./css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="./css/bootstrap.additional.css" rel="stylesheet" type="text/css" />
<link href="./css/vis.css" rel="stylesheet" type="text/css">
<script src="./jslib/jquery-1.8.3.min.js"></script>
<script src="./jslib/bootstrap.min.js"></script>
<script src="./jslib/vis.js"></script>
<script>
$(function(){
   $("#tabs").tab();
   updateNetwork("myNetwork");
});

function updateNetwork(networkElementId) {     
    // create some nodes
    var nodes = [
                {id:0,"labelHidden":"Myriel","group":1},
                {id:1,"labelHidden":"Napoleon","group":1},
                {id:2,"labelHidden":"Mlle.Baptistine","group":1},
                {id:3,"labelHidden":"Mme.Magloire","group":1},
                {id:4,"labelHidden":"CountessdeLo","group":1},
                {id:5,"labelHidden":"Geborand","group":1},
                {id:6,"labelHidden":"Champtercier","group":1},
                {id:7,"labelHidden":"Cravatte","group":1},
                {id:8,"labelHidden":"Count","group":1},
                {id:9,"labelHidden":"OldMan","group":1},
                {id:10,"labelHidden":"Labarre","group":2},
                {id:11,"labelHidden":"Valjean","group":2},
                {id:12,"labelHidden":"Marguerite","group":3},
                {id:13,"labelHidden":"Mme.deR","group":2},
                {id:14,"labelHidden":"Isabeau","group":2},
                {id:15,"labelHidden":"Gervais","group":2},
                {id:16,"labelHidden":"Tholomyes","group":3},
                {id:17,"labelHidden":"Listolier","group":3},
                {id:18,"labelHidden":"Fameuil","group":3},
                {id:19,"labelHidden":"Blacheville","group":3},
                {id:20,"labelHidden":"Favourite","group":3},
                {id:21,"labelHidden":"Dahlia","group":3},
                {id:22,"labelHidden":"Zephine","group":3},
                {id:23,"labelHidden":"Fantine","group":3},
                {id:24,"labelHidden":"Mme.Thenardier","group":4},
                {id:25,"labelHidden":"Thenardier","group":4},
                {id:26,"labelHidden":"Cosette","group":5},
                {id:27,"labelHidden":"Javert","group":4},
                {id:28,"labelHidden":"Fauchelevent","group":0},
                {id:29,"labelHidden":"Bamatabois","group":2},
                {id:30,"labelHidden":"Perpetue","group":3},
                {id:31,"labelHidden":"Simplice","group":2},
                {id:32,"labelHidden":"Scaufflaire","group":2},
                {id:33,"labelHidden":"Woman1","group":2},
                {id:34,"labelHidden":"Judge","group":2},
                {id:35,"labelHidden":"Champmathieu","group":2},
                {id:36,"labelHidden":"Brevet","group":2},
                {id:37,"labelHidden":"Chenildieu","group":2},
                {id:38,"labelHidden":"Cochepaille","group":2},
                {id:39,"labelHidden":"Pontmercy","group":4},
                {id:40,"labelHidden":"Boulatruelle","group":6},
                {id:41,"labelHidden":"Eponine","group":4},
                {id:42,"labelHidden":"Anzelma","group":4},
                {id:43,"labelHidden":"Woman2","group":5},
                {id:44,"labelHidden":"MotherInnocent","group":0},
                {id:45,"labelHidden":"Gribier","group":0},
                {id:46,"labelHidden":"Jondrette","group":7},
                {id:47,"labelHidden":"Mme.Burgon","group":7},
                {id:48,"labelHidden":"Gavroche","group":8},
                {id:49,"labelHidden":"Gillenormand","group":5},
                {id:50,"labelHidden":"Magnon","group":5},
                {id:51,"labelHidden":"Mlle.Gillenormand","group":5},
                {id:52,"labelHidden":"Mme.Pontmercy","group":5},
                {id:53,"labelHidden":"Mlle.Vaubois","group":5},
                {id:54,"labelHidden":"Lt.Gillenormand","group":5},
                {id:55,"labelHidden":"Marius","group":8},
                {id:56,"labelHidden":"BaronessT","group":5},
                {id:57,"labelHidden":"Mabeuf","group":8},
                {id:58,"labelHidden":"Enjolras","group":8},
                {id:59,"labelHidden":"Combeferre","group":8},
                {id:60,"labelHidden":"Prouvaire","group":8},
                {id:61,"labelHidden":"Feuilly","group":8},
                {id:62,"labelHidden":"Courfeyrac","group":8},
                {id:63,"labelHidden":"Bahorel","group":8},
                {id:64,"labelHidden":"Bossuet","group":8},
                {id:65,"labelHidden":"Joly","group":8},
                {id:66,"labelHidden":"Grantaire","group":8},
                {id:67,"labelHidden":"MotherPlutarch","group":9},
                {id:68,"labelHidden":"Gueulemer","group":4},
                {id:69,"labelHidden":"Babet","group":4},
                {id:70,"labelHidden":"Claquesous","group":4},
                {id:71,"labelHidden":"Montparnasse","group":4},
                {id:72,"labelHidden":"Toussaint","group":5},
                {id:73,"labelHidden":"Child1","group":10},
                {id:74,"labelHidden":"Child2","group":10},
                {id:75,"labelHidden":"Brujon","group":4},
                {id:76,"labelHidden":"Mme.Hucheloup","group":8}
            ];

    // create some edges
    var edges = [
        {"from":1,"to":0},
        {"from":2,"to":0},
        {"from":3,"to":0},
        {"from":3,"to":2},
        {"from":4,"to":0},
        {"from":5,"to":0},
        {"from":6,"to":0},
        {"from":7,"to":0},
        {"from":8,"to":0},
        {"from":9,"to":0},
        {"from":11,"to":10},
        {"from":11,"to":3},
        {"from":11,"to":2},
        {"from":11,"to":0},
        {"from":12,"to":11},
        {"from":13,"to":11},
        {"from":14,"to":11},
        {"from":15,"to":11},
        {"from":17,"to":16},
        {"from":18,"to":16},
        {"from":18,"to":17},
        {"from":19,"to":16},
        {"from":19,"to":17},
        {"from":19,"to":18},
        {"from":20,"to":16},
        {"from":20,"to":17},
        {"from":20,"to":18},
        {"from":20,"to":19},
        {"from":21,"to":16},
        {"from":21,"to":17},
        {"from":21,"to":18},
        {"from":21,"to":19},
        {"from":21,"to":20},
        {"from":22,"to":16},
        {"from":22,"to":17},
        {"from":22,"to":18},
        {"from":22,"to":19},
        {"from":22,"to":20},
        {"from":22,"to":21},
        {"from":23,"to":16},
        {"from":23,"to":17},
        {"from":23,"to":18},
        {"from":23,"to":19},
        {"from":23,"to":20},
        {"from":23,"to":21},
        {"from":23,"to":22},
        {"from":23,"to":12},
        {"from":23,"to":11},
        {"from":24,"to":23},
        {"from":24,"to":11},
        {"from":25,"to":24},
        {"from":25,"to":23},
        {"from":25,"to":11},
        {"from":26,"to":24},
        {"from":26,"to":11},
        {"from":26,"to":16},
        {"from":26,"to":25},
        {"from":27,"to":11},
        {"from":27,"to":23},
        {"from":27,"to":25},
        {"from":27,"to":24},
        {"from":27,"to":26},
        {"from":28,"to":11},
        {"from":28,"to":27},
        {"from":29,"to":23},
        {"from":29,"to":27},
        {"from":29,"to":11},
        {"from":30,"to":23},
        {"from":31,"to":30},
        {"from":31,"to":11},
        {"from":31,"to":23},
        {"from":31,"to":27},
        {"from":32,"to":11},
        {"from":33,"to":11},
        {"from":33,"to":27},
        {"from":34,"to":11},
        {"from":34,"to":29},
        {"from":35,"to":11},
        {"from":35,"to":34},
        {"from":35,"to":29},
        {"from":36,"to":34},
        {"from":36,"to":35},
        {"from":36,"to":11},
        {"from":36,"to":29},
        {"from":37,"to":34},
        {"from":37,"to":35},
        {"from":37,"to":36},
        {"from":37,"to":11},
        {"from":37,"to":29},
        {"from":38,"to":34},
        {"from":38,"to":35},
        {"from":38,"to":36},
        {"from":38,"to":37},
        {"from":38,"to":11},
        {"from":38,"to":29},
        {"from":39,"to":25},
        {"from":40,"to":25},
        {"from":41,"to":24},
        {"from":41,"to":25},
        {"from":42,"to":41},
        {"from":42,"to":25},
        {"from":42,"to":24},
        {"from":43,"to":11},
        {"from":43,"to":26},
        {"from":43,"to":27},
        {"from":44,"to":28},
        {"from":44,"to":11},
        {"from":45,"to":28},
        {"from":47,"to":46},
        {"from":48,"to":47},
        {"from":48,"to":25},
        {"from":48,"to":27},
        {"from":48,"to":11},
        {"from":49,"to":26},
        {"from":49,"to":11},
        {"from":50,"to":49},
        {"from":50,"to":24},
        {"from":51,"to":49},
        {"from":51,"to":26},
        {"from":51,"to":11},
        {"from":52,"to":51},
        {"from":52,"to":39},
        {"from":53,"to":51},
        {"from":54,"to":51},
        {"from":54,"to":49},
        {"from":54,"to":26},
        {"from":55,"to":51},
        {"from":55,"to":49},
        {"from":55,"to":39},
        {"from":55,"to":54},
        {"from":55,"to":26},
        {"from":55,"to":11},
        {"from":55,"to":16},
        {"from":55,"to":25},
        {"from":55,"to":41},
        {"from":55,"to":48},
        {"from":56,"to":49},
        {"from":56,"to":55},
        {"from":57,"to":55},
        {"from":57,"to":41},
        {"from":57,"to":48},
        {"from":58,"to":55},
        {"from":58,"to":48},
        {"from":58,"to":27},
        {"from":58,"to":57},
        {"from":58,"to":11},
        {"from":59,"to":58},
        {"from":59,"to":55},
        {"from":59,"to":48},
        {"from":59,"to":57},
        {"from":60,"to":48},
        {"from":60,"to":58},
        {"from":60,"to":59},
        {"from":61,"to":48},
        {"from":61,"to":58},
        {"from":61,"to":60},
        {"from":61,"to":59},
        {"from":61,"to":57},
        {"from":61,"to":55},
        {"from":62,"to":55},
        {"from":62,"to":58},
        {"from":62,"to":59},
        {"from":62,"to":48},
        {"from":62,"to":57},
        {"from":62,"to":41},
        {"from":62,"to":61},
        {"from":62,"to":60},
        {"from":63,"to":59},
        {"from":63,"to":48},
        {"from":63,"to":62},
        {"from":63,"to":57},
        {"from":63,"to":58},
        {"from":63,"to":61},
        {"from":63,"to":60},
        {"from":63,"to":55},
        {"from":64,"to":55},
        {"from":64,"to":62},
        {"from":64,"to":48},
        {"from":64,"to":63},
        {"from":64,"to":58},
        {"from":64,"to":61},
        {"from":64,"to":60},
        {"from":64,"to":59},
        {"from":64,"to":57},
        {"from":64,"to":11},
        {"from":65,"to":63},
        {"from":65,"to":64},
        {"from":65,"to":48},
        {"from":65,"to":62},
        {"from":65,"to":58},
        {"from":65,"to":61},
        {"from":65,"to":60},
        {"from":65,"to":59},
        {"from":65,"to":57},
        {"from":65,"to":55},
        {"from":66,"to":64},
        {"from":66,"to":58},
        {"from":66,"to":59},
        {"from":66,"to":62},
        {"from":66,"to":65},
        {"from":66,"to":48},
        {"from":66,"to":63},
        {"from":66,"to":61},
        {"from":66,"to":60},
        {"from":67,"to":57},
        {"from":68,"to":25},
        {"from":68,"to":11},
        {"from":68,"to":24},
        {"from":68,"to":27},
        {"from":68,"to":48},
        {"from":68,"to":41},
        {"from":69,"to":25},
        {"from":69,"to":68},
        {"from":69,"to":11},
        {"from":69,"to":24},
        {"from":69,"to":27},
        {"from":69,"to":48},
        {"from":69,"to":41},
        {"from":70,"to":25},
        {"from":70,"to":69},
        {"from":70,"to":68},
        {"from":70,"to":11},
        {"from":70,"to":24},
        {"from":70,"to":27},
        {"from":70,"to":41},
        {"from":70,"to":58},
        {"from":71,"to":27},
        {"from":71,"to":69},
        {"from":71,"to":68},
        {"from":71,"to":70},
        {"from":71,"to":11},
        {"from":71,"to":48},
        {"from":71,"to":41},
        {"from":71,"to":25},
        {"from":72,"to":26},
        {"from":72,"to":27},
        {"from":72,"to":11},
        {"from":73,"to":48},
        {"from":74,"to":48},
        {"from":74,"to":73},
        {"from":75,"to":69},
        {"from":75,"to":68},
        {"from":75,"to":25},
        {"from":75,"to":48},
        {"from":75,"to":41},
        {"from":75,"to":70},
        {"from":75,"to":71},
        {"from":76,"to":64},
        {"from":76,"to":65},
        {"from":76,"to":66},
        {"from":76,"to":63},
        {"from":76,"to":62},
        {"from":76,"to":48},
        {"from":76,"to":58}
    ];

    // create a network
    var container = document.getElementById(networkElementId);
    var data = {
        nodes: nodes,
        edges: edges
    };
    var options = {nodes: {shape:'circle'},stabilize: false};
    var network = new vis.Network(container, data, options);
}
</script>
</head>
<body>

<div role="tabpanel">

  <!-- Nav tabs -->
  <ul id="tabs" class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active"><a href="#tab1" aria-controls="tab1" role="tab" data-toggle="tab">Tab1</a></li>
    <li role="presentation"><a href="#tab2" aria-controls="tab2" role="tab" data-toggle="tab">Tab2</a></li>
    <li role="presentation"><a href="#tab3" aria-controls="tab3" role="tab" data-toggle="tab">Tab3</a></li>
  </ul>

<div class="tab-content">
   <div role="tabpanel" class="tab-pane active" id="tab1">
      This is tab 1 (Active by default)
   </div>

   <div role="tabpanel" class="tab-pane active" id="tab2">
       <div id="myNetwork" style = "height:500px; margin-top:10px;"></div>
   </div>
  
   <div role="tabpanel" class="tab-pane active" id="tab3">
     This is tab 3
   </div>
</div>

</div>

</body>
</html>

Well the above code does not work as the network is not displayed in the tab page. The cause seems to be that the vis.js requires a visible <div> to draw the network. So finally i settled for a solution in which the network is created in the "myNetwork" <div> element when the tab page "tab2" is shown. Below is the working implementation.
<html>
<head>
<link href="./css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="./css/bootstrap.additional.css" rel="stylesheet" type="text/css" />
<link href="./css/vis.css" rel="stylesheet" type="text/css">
<script src="./jslib/jquery-1.8.3.min.js"></script>
<script src="./jslib/bootstrap.min.js"></script>
<script src="./jslib/vis.js"></script>
<script>
$(function(){
   $("#tabs").tab();
    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    var target = $(e.target).attr("href");
    if(target=="#tab2")
    {
     updateNetwork("myNetwork");
    }
   });
   
});

function updateNetwork(networkElementId) {     
    // create some nodes
    var nodes = [
                {id:0,"labelHidden":"Myriel","group":1},
                {id:1,"labelHidden":"Napoleon","group":1},
                {id:2,"labelHidden":"Mlle.Baptistine","group":1},
                {id:3,"labelHidden":"Mme.Magloire","group":1},
                {id:4,"labelHidden":"CountessdeLo","group":1},
                {id:5,"labelHidden":"Geborand","group":1},
                {id:6,"labelHidden":"Champtercier","group":1},
                {id:7,"labelHidden":"Cravatte","group":1},
                {id:8,"labelHidden":"Count","group":1},
                {id:9,"labelHidden":"OldMan","group":1},
                {id:10,"labelHidden":"Labarre","group":2},
                {id:11,"labelHidden":"Valjean","group":2},
                {id:12,"labelHidden":"Marguerite","group":3},
                {id:13,"labelHidden":"Mme.deR","group":2},
                {id:14,"labelHidden":"Isabeau","group":2},
                {id:15,"labelHidden":"Gervais","group":2},
                {id:16,"labelHidden":"Tholomyes","group":3},
                {id:17,"labelHidden":"Listolier","group":3},
                {id:18,"labelHidden":"Fameuil","group":3},
                {id:19,"labelHidden":"Blacheville","group":3},
                {id:20,"labelHidden":"Favourite","group":3},
                {id:21,"labelHidden":"Dahlia","group":3},
                {id:22,"labelHidden":"Zephine","group":3},
                {id:23,"labelHidden":"Fantine","group":3},
                {id:24,"labelHidden":"Mme.Thenardier","group":4},
                {id:25,"labelHidden":"Thenardier","group":4},
                {id:26,"labelHidden":"Cosette","group":5},
                {id:27,"labelHidden":"Javert","group":4},
                {id:28,"labelHidden":"Fauchelevent","group":0},
                {id:29,"labelHidden":"Bamatabois","group":2},
                {id:30,"labelHidden":"Perpetue","group":3},
                {id:31,"labelHidden":"Simplice","group":2},
                {id:32,"labelHidden":"Scaufflaire","group":2},
                {id:33,"labelHidden":"Woman1","group":2},
                {id:34,"labelHidden":"Judge","group":2},
                {id:35,"labelHidden":"Champmathieu","group":2},
                {id:36,"labelHidden":"Brevet","group":2},
                {id:37,"labelHidden":"Chenildieu","group":2},
                {id:38,"labelHidden":"Cochepaille","group":2},
                {id:39,"labelHidden":"Pontmercy","group":4},
                {id:40,"labelHidden":"Boulatruelle","group":6},
                {id:41,"labelHidden":"Eponine","group":4},
                {id:42,"labelHidden":"Anzelma","group":4},
                {id:43,"labelHidden":"Woman2","group":5},
                {id:44,"labelHidden":"MotherInnocent","group":0},
                {id:45,"labelHidden":"Gribier","group":0},
                {id:46,"labelHidden":"Jondrette","group":7},
                {id:47,"labelHidden":"Mme.Burgon","group":7},
                {id:48,"labelHidden":"Gavroche","group":8},
                {id:49,"labelHidden":"Gillenormand","group":5},
                {id:50,"labelHidden":"Magnon","group":5},
                {id:51,"labelHidden":"Mlle.Gillenormand","group":5},
                {id:52,"labelHidden":"Mme.Pontmercy","group":5},
                {id:53,"labelHidden":"Mlle.Vaubois","group":5},
                {id:54,"labelHidden":"Lt.Gillenormand","group":5},
                {id:55,"labelHidden":"Marius","group":8},
                {id:56,"labelHidden":"BaronessT","group":5},
                {id:57,"labelHidden":"Mabeuf","group":8},
                {id:58,"labelHidden":"Enjolras","group":8},
                {id:59,"labelHidden":"Combeferre","group":8},
                {id:60,"labelHidden":"Prouvaire","group":8},
                {id:61,"labelHidden":"Feuilly","group":8},
                {id:62,"labelHidden":"Courfeyrac","group":8},
                {id:63,"labelHidden":"Bahorel","group":8},
                {id:64,"labelHidden":"Bossuet","group":8},
                {id:65,"labelHidden":"Joly","group":8},
                {id:66,"labelHidden":"Grantaire","group":8},
                {id:67,"labelHidden":"MotherPlutarch","group":9},
                {id:68,"labelHidden":"Gueulemer","group":4},
                {id:69,"labelHidden":"Babet","group":4},
                {id:70,"labelHidden":"Claquesous","group":4},
                {id:71,"labelHidden":"Montparnasse","group":4},
                {id:72,"labelHidden":"Toussaint","group":5},
                {id:73,"labelHidden":"Child1","group":10},
                {id:74,"labelHidden":"Child2","group":10},
                {id:75,"labelHidden":"Brujon","group":4},
                {id:76,"labelHidden":"Mme.Hucheloup","group":8}
            ];

    // create some edges
    var edges = [
        {"from":1,"to":0},
        {"from":2,"to":0},
        {"from":3,"to":0},
        {"from":3,"to":2},
        {"from":4,"to":0},
        {"from":5,"to":0},
        {"from":6,"to":0},
        {"from":7,"to":0},
        {"from":8,"to":0},
        {"from":9,"to":0},
        {"from":11,"to":10},
        {"from":11,"to":3},
        {"from":11,"to":2},
        {"from":11,"to":0},
        {"from":12,"to":11},
        {"from":13,"to":11},
        {"from":14,"to":11},
        {"from":15,"to":11},
        {"from":17,"to":16},
        {"from":18,"to":16},
        {"from":18,"to":17},
        {"from":19,"to":16},
        {"from":19,"to":17},
        {"from":19,"to":18},
        {"from":20,"to":16},
        {"from":20,"to":17},
        {"from":20,"to":18},
        {"from":20,"to":19},
        {"from":21,"to":16},
        {"from":21,"to":17},
        {"from":21,"to":18},
        {"from":21,"to":19},
        {"from":21,"to":20},
        {"from":22,"to":16},
        {"from":22,"to":17},
        {"from":22,"to":18},
        {"from":22,"to":19},
        {"from":22,"to":20},
        {"from":22,"to":21},
        {"from":23,"to":16},
        {"from":23,"to":17},
        {"from":23,"to":18},
        {"from":23,"to":19},
        {"from":23,"to":20},
        {"from":23,"to":21},
        {"from":23,"to":22},
        {"from":23,"to":12},
        {"from":23,"to":11},
        {"from":24,"to":23},
        {"from":24,"to":11},
        {"from":25,"to":24},
        {"from":25,"to":23},
        {"from":25,"to":11},
        {"from":26,"to":24},
        {"from":26,"to":11},
        {"from":26,"to":16},
        {"from":26,"to":25},
        {"from":27,"to":11},
        {"from":27,"to":23},
        {"from":27,"to":25},
        {"from":27,"to":24},
        {"from":27,"to":26},
        {"from":28,"to":11},
        {"from":28,"to":27},
        {"from":29,"to":23},
        {"from":29,"to":27},
        {"from":29,"to":11},
        {"from":30,"to":23},
        {"from":31,"to":30},
        {"from":31,"to":11},
        {"from":31,"to":23},
        {"from":31,"to":27},
        {"from":32,"to":11},
        {"from":33,"to":11},
        {"from":33,"to":27},
        {"from":34,"to":11},
        {"from":34,"to":29},
        {"from":35,"to":11},
        {"from":35,"to":34},
        {"from":35,"to":29},
        {"from":36,"to":34},
        {"from":36,"to":35},
        {"from":36,"to":11},
        {"from":36,"to":29},
        {"from":37,"to":34},
        {"from":37,"to":35},
        {"from":37,"to":36},
        {"from":37,"to":11},
        {"from":37,"to":29},
        {"from":38,"to":34},
        {"from":38,"to":35},
        {"from":38,"to":36},
        {"from":38,"to":37},
        {"from":38,"to":11},
        {"from":38,"to":29},
        {"from":39,"to":25},
        {"from":40,"to":25},
        {"from":41,"to":24},
        {"from":41,"to":25},
        {"from":42,"to":41},
        {"from":42,"to":25},
        {"from":42,"to":24},
        {"from":43,"to":11},
        {"from":43,"to":26},
        {"from":43,"to":27},
        {"from":44,"to":28},
        {"from":44,"to":11},
        {"from":45,"to":28},
        {"from":47,"to":46},
        {"from":48,"to":47},
        {"from":48,"to":25},
        {"from":48,"to":27},
        {"from":48,"to":11},
        {"from":49,"to":26},
        {"from":49,"to":11},
        {"from":50,"to":49},
        {"from":50,"to":24},
        {"from":51,"to":49},
        {"from":51,"to":26},
        {"from":51,"to":11},
        {"from":52,"to":51},
        {"from":52,"to":39},
        {"from":53,"to":51},
        {"from":54,"to":51},
        {"from":54,"to":49},
        {"from":54,"to":26},
        {"from":55,"to":51},
        {"from":55,"to":49},
        {"from":55,"to":39},
        {"from":55,"to":54},
        {"from":55,"to":26},
        {"from":55,"to":11},
        {"from":55,"to":16},
        {"from":55,"to":25},
        {"from":55,"to":41},
        {"from":55,"to":48},
        {"from":56,"to":49},
        {"from":56,"to":55},
        {"from":57,"to":55},
        {"from":57,"to":41},
        {"from":57,"to":48},
        {"from":58,"to":55},
        {"from":58,"to":48},
        {"from":58,"to":27},
        {"from":58,"to":57},
        {"from":58,"to":11},
        {"from":59,"to":58},
        {"from":59,"to":55},
        {"from":59,"to":48},
        {"from":59,"to":57},
        {"from":60,"to":48},
        {"from":60,"to":58},
        {"from":60,"to":59},
        {"from":61,"to":48},
        {"from":61,"to":58},
        {"from":61,"to":60},
        {"from":61,"to":59},
        {"from":61,"to":57},
        {"from":61,"to":55},
        {"from":62,"to":55},
        {"from":62,"to":58},
        {"from":62,"to":59},
        {"from":62,"to":48},
        {"from":62,"to":57},
        {"from":62,"to":41},
        {"from":62,"to":61},
        {"from":62,"to":60},
        {"from":63,"to":59},
        {"from":63,"to":48},
        {"from":63,"to":62},
        {"from":63,"to":57},
        {"from":63,"to":58},
        {"from":63,"to":61},
        {"from":63,"to":60},
        {"from":63,"to":55},
        {"from":64,"to":55},
        {"from":64,"to":62},
        {"from":64,"to":48},
        {"from":64,"to":63},
        {"from":64,"to":58},
        {"from":64,"to":61},
        {"from":64,"to":60},
        {"from":64,"to":59},
        {"from":64,"to":57},
        {"from":64,"to":11},
        {"from":65,"to":63},
        {"from":65,"to":64},
        {"from":65,"to":48},
        {"from":65,"to":62},
        {"from":65,"to":58},
        {"from":65,"to":61},
        {"from":65,"to":60},
        {"from":65,"to":59},
        {"from":65,"to":57},
        {"from":65,"to":55},
        {"from":66,"to":64},
        {"from":66,"to":58},
        {"from":66,"to":59},
        {"from":66,"to":62},
        {"from":66,"to":65},
        {"from":66,"to":48},
        {"from":66,"to":63},
        {"from":66,"to":61},
        {"from":66,"to":60},
        {"from":67,"to":57},
        {"from":68,"to":25},
        {"from":68,"to":11},
        {"from":68,"to":24},
        {"from":68,"to":27},
        {"from":68,"to":48},
        {"from":68,"to":41},
        {"from":69,"to":25},
        {"from":69,"to":68},
        {"from":69,"to":11},
        {"from":69,"to":24},
        {"from":69,"to":27},
        {"from":69,"to":48},
        {"from":69,"to":41},
        {"from":70,"to":25},
        {"from":70,"to":69},
        {"from":70,"to":68},
        {"from":70,"to":11},
        {"from":70,"to":24},
        {"from":70,"to":27},
        {"from":70,"to":41},
        {"from":70,"to":58},
        {"from":71,"to":27},
        {"from":71,"to":69},
        {"from":71,"to":68},
        {"from":71,"to":70},
        {"from":71,"to":11},
        {"from":71,"to":48},
        {"from":71,"to":41},
        {"from":71,"to":25},
        {"from":72,"to":26},
        {"from":72,"to":27},
        {"from":72,"to":11},
        {"from":73,"to":48},
        {"from":74,"to":48},
        {"from":74,"to":73},
        {"from":75,"to":69},
        {"from":75,"to":68},
        {"from":75,"to":25},
        {"from":75,"to":48},
        {"from":75,"to":41},
        {"from":75,"to":70},
        {"from":75,"to":71},
        {"from":76,"to":64},
        {"from":76,"to":65},
        {"from":76,"to":66},
        {"from":76,"to":63},
        {"from":76,"to":62},
        {"from":76,"to":48},
        {"from":76,"to":58}
    ];

    // create a network
    var container = document.getElementById(networkElementId);
    var data = {
        nodes: nodes,
        edges: edges
    };
    var options = {nodes: {shape:'circle'},stabilize: false};
    var network = new vis.Network(container, data, options);
}
</script>
</head>
<body>

<div role="tabpanel">

  <!-- Nav tabs -->
  <ul id="tabs" class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active"><a href="#tab1" aria-controls="tab1" role="tab" data-toggle="tab">Tab1</a></li>
    <li role="presentation"><a href="#tab2" aria-controls="tab2" role="tab" data-toggle="tab">Tab2</a></li>
    <li role="presentation"><a href="#tab3" aria-controls="tab3" role="tab" data-toggle="tab">Tab3</a></li>
  </ul>

<div class="tab-content">
   <div role="tabpanel" class="tab-pane active" id="tab1">
      This is tab 1 (Active by default)
   </div>

   <div role="tabpanel" class="tab-pane active" id="tab2">
       <div id="myNetwork" style = "height:500px; margin-top:10px;"></div>
   </div>
  
   <div role="tabpanel" class="tab-pane active" id="tab3">
     This is tab 3
   </div>
</div>

</div>

</body>
</html>



Bootstrap: Display a map in a tab page within a tab control

Recently i was working with bootstrap and i needed to display a map within a tab page of a tab control. The task look simple enough, below is the html and javascript codes:

<html>
<head>
<link href="./css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="./css/bootstrap.additional.css" rel="stylesheet" type="text/css" />
<script src="./jslib/jquery-1.8.3.min.js"></script>
<script src="./jslib/bootstrap.min.js"></script>
<script src="./jslib/OpenLayers.js"></script>
<script>
$(function(){
   $("#tabs").tab();
   var lat = 1.3000;
   var lon = 103.8000;
   updateMap("myMap", lon, lat);
});

function updateMap(mapElementId, lon, lat) {     
    var layer = new OpenLayers.Layer.OSM();

    map = new OpenLayers.Map(mapElementId);
    map.addLayer(layer);
    
    var epsg4326 =  new OpenLayers.Projection("EPSG:4326");
    var projectTo = map.getProjectionObject(); 
    var lonLat = new OpenLayers.LonLat(lon, lat).transform(epsg4326, projectTo);
    var zoom = 10;
    var popup = null;
    
    map.setCenter (lonLat, zoom);
}
</script>
</head>
<body>

<div role="tabpanel">

  <!-- Nav tabs -->
  <ul id="tabs" class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active"><a href="#tab1" aria-controls="tab1" role="tab" data-toggle="tab">Tab1</a></li>
    <li role="presentation"><a href="#tab2" aria-controls="tab2" role="tab" data-toggle="tab">Tab2</a></li>
    <li role="presentation"><a href="#tab3" aria-controls="tab3" role="tab" data-toggle="tab">Tab3</a></li>
  </ul>

<div class="tab-content">
   <div role="tabpanel" class="tab-pane active" id="tab1">
      This is tab 1 (Active by default)
   </div>

   <div role="tabpanel" class="tab-pane active" id="tab2">
      <div id="myMap" style="width:440px; height:300px; vertical-align: middle; margin-top: 10px; margin-bottom: 10px">
   </div>
  
   <div role="tabpanel" class="tab-pane active" id="tab3">
     This is tab 3
   </div>
</div>

</div>

</body>
</html>

I expected it to work, but somehow the map fails to show up. After some digging, it seems that the map fails to realize it height in the tab page if the tab page is not initially active. The solution is to add  style="height:100%" to the  <div class="tab-content"> so that it becomes like  <div class="tab-content" style="height:100%">.

Tuesday, July 16, 2013

Getting JqPlot to work inside a JQuery UI Tab

Jqplot is a very simple jquery-based plotting library for displaying simple plotting charts on html page, however, having a jqplot <div> in a jquery ui container such as tab and not having it displayed as default (e.g. having the jqplot as the second tab page instead of the default first tab page), the jqplot <div> will not display any plot. For example the following code will not work for the jqplot:

<html>
<head>
<link rel="stylesheet" type="text/css" href="jquery-ui/themes/base/jquery.ui.all.css">
<link rel="stylesheet" type="text/css" href="jquery-ui/demos.css">
<link rel="stylesheet" type="text/css" href="jqplot/jquery.jqplot.min.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="jqplot/jquery.jqplot.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.barRenderer.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.pieRenderer.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.pointLabels.min.js"></script>
<script src="jquery-ui/ui/jquery.ui.core.js"></script>
<script src="jquery-ui/ui/jquery.ui.widget.js"></script>
<script src="jquery-ui/ui/jquery.ui.tabs.js"></script>
<script type="text/javascript">
$(function(){
$( "#tabs" ).tabs();

    var s1 = [1, 2, 3];
    // Can specify a custom tick Array.
    // Ticks should match up one for each y value (category) in the series.
    var ticks = ["Val1", "Val2", "Val3"];
     
    var plot1 = $.jqplot('chart1', [s1], {
        // The "seriesDefaults" option is an options object that will
        // be applied to all series in the chart.
        seriesDefaults:{
            renderer:$.jqplot.BarRenderer,
            rendererOptions: {fillToZero: true}
        },
        // Custom labels for the series are specified with the "label"
        // option on the series option.  Here a series option object
        // is specified for each series.
        series:[
            {label:'Search Query'}
        ],
        // Show the legend and put it outside the grid, but inside the
        // plot container, shrinking the grid to accomodate the legend.
        // A value of "outside" would not shrink the grid and allow
        // the legend to overflow the container.
        legend: {
            show: true,
            placement: 'outsideGrid'
        },
        axes: {
            // Use a category axis on the x axis and use our custom ticks.
            xaxis: {
                renderer: $.jqplot.CategoryAxisRenderer,
                ticks: ticks
            },
            // Pad the y axis just a little so bars can get close to, but
            // not touch, the grid boundaries.  1.2 is the default padding.
            yaxis: {
                pad: 1.05,
                tickOptions: {formatString: '%d'}
            }
        }
    });
var s2 = [["Val1":1], ["Val2":2], ["Val3":3]];
         
    var plot2 = $.jqplot('pie', [s2], {
        grid: {
            drawBorder: false, 
            drawGridlines: false,
            background: '#ffffff',
            shadow:false
        },
        axesDefaults: {
             
        },
        seriesDefaults:{
            renderer:$.jqplot.PieRenderer,
            rendererOptions: {
                showDataLabels: true
            }
        },
        legend: {
            show: true,
            rendererOptions: {
                numberRows: 1
            },
            location: 's'
        }
    }); 
$('#tabs').bind('tabsshow', function(event, ui) {
 if (ui.index === 1 && plot1._drawCount === 0) {
plot1.replot();
 }
 else if (ui.index === 2 && plot2._drawCount === 0) {
plot2.replot();
 }
});

});
</script>
</head>
<body>
<div id="tabs" style="min-height:500px">
<ul>
<li><a href="#tabs-1">Tabular Data</a></li>
<li><a href="#tabs-2">Histogram</a></li>
<li><a href="#tabs-3">Pie Chart</a></li>
</ul>
       <div id="tabs-1">
First Tab Page
</div>
<div id="tabs-2">
<div id="chart1" data-height="480px" data-width="960px" style="margin-top:20px; margin-left:20px;"></div>
</div>
<div id="tabs-3">
<div id="pie" data-height="480px" data-width="960px" style="margin-top:20px; margin-left:20px;"></div>
</div>
</div>
</body>
</html>

The solution is to call the jqplot element's replot() method when a tab page is selected by adding the highlighted section shown below:

<html>
<head>
<link rel="stylesheet" type="text/css" href="jquery-ui/themes/base/jquery.ui.all.css">
<link rel="stylesheet" type="text/css" href="jquery-ui/demos.css">
<link rel="stylesheet" type="text/css" href="jqplot/jquery.jqplot.min.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="jqplot/jquery.jqplot.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.barRenderer.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.pieRenderer.min.js"></script>
<script type="text/javascript" src="jqplot/plugins/jqplot.pointLabels.min.js"></script>
<script src="jquery-ui/ui/jquery.ui.core.js"></script>
<script src="jquery-ui/ui/jquery.ui.widget.js"></script>
<script src="jquery-ui/ui/jquery.ui.tabs.js"></script>
<script type="text/javascript">
$(function(){
$( "#tabs" ).tabs();

    var s1 = [1, 2, 3];
    // Can specify a custom tick Array.
    // Ticks should match up one for each y value (category) in the series.
    var ticks = ["Val1", "Val2", "Val3"];
     
    var plot1 = $.jqplot('chart1', [s1], {
        // The "seriesDefaults" option is an options object that will
        // be applied to all series in the chart.
        seriesDefaults:{
            renderer:$.jqplot.BarRenderer,
            rendererOptions: {fillToZero: true}
        },
        // Custom labels for the series are specified with the "label"
        // option on the series option.  Here a series option object
        // is specified for each series.
        series:[
            {label:'Search Query'}
        ],
        // Show the legend and put it outside the grid, but inside the
        // plot container, shrinking the grid to accomodate the legend.
        // A value of "outside" would not shrink the grid and allow
        // the legend to overflow the container.
        legend: {
            show: true,
            placement: 'outsideGrid'
        },
        axes: {
            // Use a category axis on the x axis and use our custom ticks.
            xaxis: {
                renderer: $.jqplot.CategoryAxisRenderer,
                ticks: ticks
            },
            // Pad the y axis just a little so bars can get close to, but
            // not touch, the grid boundaries.  1.2 is the default padding.
            yaxis: {
                pad: 1.05,
                tickOptions: {formatString: '%d'}
            }
        }
    });
var s2 = [["Val1":1], ["Val2":2], ["Val3":3]];
         
    var plot2 = $.jqplot('pie', [s2], {
        grid: {
            drawBorder: false, 
            drawGridlines: false,
            background: '#ffffff',
            shadow:false
        },
        axesDefaults: {
             
        },
        seriesDefaults:{
            renderer:$.jqplot.PieRenderer,
            rendererOptions: {
                showDataLabels: true
            }
        },
        legend: {
            show: true,
            rendererOptions: {
                numberRows: 1
            },
            location: 's'
        }
    }); 
$('#tabs').bind('tabsshow', function(event, ui) {
  if (ui.index === 1 && plot1._drawCount === 0) {
plot1.replot();
  }
  else if (ui.index === 2 && plot2._drawCount === 0) {
plot2.replot();
  }
});

});
</script>
</head>
<body>
<div id="tabs" style="min-height:500px">
<ul>
<li><a href="#tabs-1">Tabular Data</a></li>
<li><a href="#tabs-2">Histogram</a></li>
<li><a href="#tabs-3">Pie Chart</a></li>
</ul>
       <div id="tabs-1">
First Tab Page
</div>
<div id="tabs-2">
<div id="chart1" data-height="480px" data-width="960px" style="margin-top:20px; margin-left:20px;"></div>
</div>
<div id="tabs-3">
<div id="pie" data-height="480px" data-width="960px" style="margin-top:20px; margin-left:20px;"></div>
</div>
</div>
</body>
</html>

Sunday, July 14, 2013

A simple shopping cart integration with eNETS and WorldPay using jQuery and PHP with database logging

Below is the demo code written in jQuery, PHP for a simple shopping cart which performs transaction with eNETS or WorldPay and log the records to the server:

http://www.4shared.com/zip/C-bgFisq/shopping_cart.html

The basic ideas is like this:  after the user enters the registration information and click "Checkout" button, the javascript on the client web browser will perform validation (e.g. check whether required fields are entered, whether the amount is greater than 0, etc). If the validation is correct, then the registration information will first post to the server as a record, which then returns a transaction reference number to the web browser. If the transaction reference number from the server is correctly returned, the javascript on the client web browser will post the form with the updated transaction reference number as well as the total amount to the enet (or worldpay), which then takes over the transaction.

  • The enets.html contains the web page and javascripts for working with eNETS, the javascript first post the form data to the log.php to be logged in the MySQL Server, and submit the form to eNETS gateway with the transaction reference received returned by the log.php
  • The worldpay.html contains the web page and javascript for working with WorldPay, the javascript first post the form data to the log.php to be logged in the MySQL Server, and submit the form to WorldPay gateway with the transaction reference received returned by the log.php
  • The log.php contains the PHP codes that logs that transaction data to the MySQL server, then returns the id of the last inserted transaction as the transaction reference to the jQuery post script which post the request.



Tuesday, January 11, 2011

Enable jScrollPane working with jquery TabControl

If a <div> element "scroll-pane" which requires to be rendered using jScrollPane is within another <div> element "tabs" rendered with jquery ui TabControl, it is necessary to call jScrollPane() method on the "scroll-pane" after "tabs" calls its tabs() method by calling $("#scroll-pane").jScrollPane() in "tabs" onShow event trigger. The jquery code look likes this:

 $(function(){
                    $( "#tabs" ).tabs({
                     show: function(event, ui) 
                     {
                        $("#scroll-pane").jScrollPane();
                     }
                    });                    
            });