Graphs in dynamic web pages

Using BFO Graphs in dynamic web pages

The traditional approach to using the BFO Graph Library in web pages has been to use the JSP tag library so that the server processes XML in JSP pages and replaces it with generated graphs.

However if you want to include BFO graphs in non JSP web pages that use AJAX to load data dynamically then the tag library is not very useful. Although the Graph Library has a SOAP interface for web service access SOAP is not well suited to being used from web pages, so instead we will use the plain XML interface to the Graph Library to dynamically add charts to web pages.

By sending XML data to the Graph library's servlet with the xml-html format option we can recieve back all the data we need to embed the chart into a web page. You can read about the 'xml-html' format option, as well as the other 'xml' and 'xml-raw' options in the Graph Library user guide.

Sending the XML to the servlet can be done quite easily with some JavaScript:

function getChart() {
  var xml2 = "<axesgraph ....</axesgraph>";

  // Obtain XmlHttpRequest object
  var req = getHTTPRequest(); 
  req.open("POST", 
      "http://localhost:8080/graph/GraphServlet/xml-html");
  req.onreadystatechange = function() {
    if (req.readyState != 4) return;
    if (req.status != 200) return;

    // wrap result in single root 'xml' element
    gotChart("<xml>" + req.responseText + "</xml>");
  }
  req.setRequestHeader("Content-Type", 
      "application/x-www-form/urlencoded");
  req.send(xml2);
}
  

The chunk of XML is just standard BFO Graph XML (omitted here for the sake of readability), including an 'onmousemove' event handler to add some interactivity to the graph.

The rest of the JavaScript sends that XML to the URL of the Graph Library servlet, adding an output format 'xml-html' in this case, to give a final URL of something like 'http://localhost:8080/graph/servlet/GraphServlet/xml-html'. This JavaScript then passes the returned XML data is to the 'gotChart()' JavaScript method.

N.B. Due to JavaScript security restrictions the server in this URL must match the server name that the HTML document was loaded from exactly, or this will not work. See this article for more information.

The XML returned from this has 3 main elements:

  • map An optional HTML imagemap element containing information about the areas on the chart that should react to mouse move events. Not included if the graph doesn't specify any interactive features.
  • script An optional HTML script element containing JavaScript methods invoked from the map element. Again, not included if the graph is not interactive.
  • img An HTML img element pointing at the URL of the generated chart image.

The 'gotChart()' method below simply processes these XML elements, adding 'map' and 'script' into the current HTML document if they exist, and replacing the HTML on an existing 'chart' element with the 'img' element to display the graph itself.

function gotChart(xmlObj) {
  var dom = (new DOMParser().parseFromString(xmlObj, "text/xml"));

  // Add in the 'map' element 
  var map = dom.getElementsByTagName("map")[0];    
  if (map) {
    var newmap = document.createElement("map");
    newmap.innerHTML = new XMLSerializer().serializeToString(map); 
    newmap = document.getElementsByTagName("head")[0].appendChild(newmap);
    var tmp = newmap.removeChild(newmap.firstChild);
    newmap.parentNode.appendChild(tmp);
    newmap.parentNode.removeChild(newmap);
  }
  
  // handle <script> element
  var script = dom.getElementsByTagName("script")[0];
  if (script) {
    // create new element in current DOM
    var newscript = document.createElement("script");
    // get rid of '<script..' wrapper'
    var child = script.firstChild;
    var js = "";
    while (child)  {
        js += child.textContent;
        child = child.nextSibling;
    }

    // set up new script element to match 
    newscript.text = js;
    newscript.defer = true;
    newscript.language="javascript";
    newscript.type="text/javascript";
    newscript = 
      document.getElementsByTagName("head")[0].appendChild(newscript);
  }

  // replace the HTML of the 'chart' element 
  // in the current page with the IMG tag for the 
  // generated chart, causing it to display
  var img = dom.getElementsByTagName("img")[0];
  if (img) {
    document.getElementById("chart").innerHTML 
      = new XMLSerializer().serializeToString(img);
  }
}

That is almost all that is required. The complete source for the HTML and JavaScript described above can be found here which is a simple page that posts the XML and processes the result when you click on the button.

It should be easy to integrate such dynamic chart functionality into your own web pages - you can try it out on this page by clicking the 'Get Graph' button below.

Get Graph