I am using a Google Line Chart to graph values pulled from a database using JSP. I currently have have it working. The data.addColumn statements are generated from a database query when the page loads.
My problem is that I also want to have a couple of comboboxes that can be used to pick min and max values for the x-axis and then update the graph. Currently the only way I can think to accomplish this is refresh the page with new get parameters.
I would prefer to somehow only refresh the chart itself without reloading the entire page. Is this possible? Is there a way to overwrite the script tag and then reload the chart? Or is there some other way?
EDIT: I am having trouble figuring out how to pass the data from the database over to the loading page. Here is my code:
loader.html (page the holds the chart and date fields):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('visualization', '1', {packages: ['corechart']});
</script>
<script type="text/javascript">
function loadChart()
{
var xmlhttp;
var minDate = document.getElementById('startDate').value;
var maxDate = document.getElementById('endDate').value;
if (!minDate)
minDate = 'none';
if (!maxDate)
maxDate = 'none';
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById('lineChart').innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "chart-loader.jsp?min=" + minDate + '&max=' + maxDate, true);
xmlhttp.send();
}
</script>
</head>
<body>
<div id="container">
<div id="lineChart"></div>
<div id="startDateBox">
<label for="startDate">Min Date:</label>
<input id="startDate" type="text" />
</div>
<div id="endDateBox">
<label for="endDate">Max Date:</label>
<input id="endDate" type="text" />
</div>
<input type="button" value="Update" id="updateBtn" onclick="loadChart()" />
</div> <!-- End container -->
</body>
</html>
chart-loader.jsp (supposed to get data and load the chart)
<%@ page import="java.sql.*, java.util.ArrayList" %>
<%
Connection conn;
try {
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://...", "user", "pass");
}
catch(SQLException e)
{
out.println("SQLException: " + e.getMessage() + "<br/>");
while((e = e.getNextException()) != null)
out.println(e.getMessage() + "<br/>");
throw new UnavailableException(this, "Cannot connect with the specified database.");
}
String data = "";
String minDate = (String)request.getParameter("min");
String maxDate = (String)request.getParameter("max");
try
{
ResultSet rs;
Statement stmt = conn.createStatement();
if (minDate.equals("none") || maxDate.equals("none")) // First load, use whole table
{
rs = stmt.executeQuery("SELECT ...");
}
// ... more possible queries
ArrayList<String> ptVals = new ArrayList<String>();
ArrayList<String> colDates = new ArrayList<String>();
while (rs.next())
{
ptVals.add(rs.getString("avgvalue"));
colDates.add(rs.getString("collectiondate"));
}
// ptVals.size()
for (int i = 0; i < 5; i++)
data += "\t\t\tdata.addRow(['" + colDates.get(i) + "'," + ptVals.get(i) + "]);\n";
// ... Use out.print to spit out script.
}
catch(SQLException e)
{
data = "SQLException: " + e.getMessage() + "<br/>";
while((e = e.getNextException()) != null)
data += e.getMessage() + "<br/>";
}
finally
{ // Clean up resources, close the connection.
if(conn != null)
{
try { conn.close(); }
catch (Exception ignored) {}
}
}
%>
Original script to load the chart
<script type="text/javascript">
function drawVisualization()
{
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Date');
data.addColumn('number', 'Temperature');
data.addRow(["01/01/11", 70.2]);
data.addRow(["01/02/11", 70.0]);
data.addRow(["01/03/11", 69.8]);
data.addRow(["01/04/11", 70.1]);
// Create and draw the visualization.
new google.visualization.LineChart(document.getElementById('lineChart')).
draw(data, {backgroundColor: 'transparent',
width: 700, height: 400,
legend: 'none',
hAxis: {title: 'Dates', titleTextStyle: {color: 'black', fontSize: 12, fontName: 'Verdana, Arial'}},
vAxis: {title: 'Temperature', titleTextStyle: {color: 'black', fontSize: 12, fontName: 'Verdana, Arial'}},
chartArea: {left: 80, top: 20}
}
);
}
google.setOnLoadCallback(drawVisualization);
</script>
Thanks,
Ryan
I was able to get this to work with Google Visualization API. Here’s how:
I have an HTML page that has a container
divfor the graph.<div id="lineChart"></div>Next I have two JavaScript functions in the HTML page. The
getChartData()function is an AJAX function that gets the date range from two input fields and sends them to a JSP page. The JSP page uses the dates to query the database for records in that range, formats them as a JavaScript object, and sends it back to the HTML page usingout.print().Once the HTML page receives the data, it uses
eval()to set the received text as a JavaScript object. Finally, the data object is sent to the second JavaScript function,loadChart(), which uses the data to call the Google functions and load the chart into thediv.Note: using
eval()to set theresponseTextto a JavaScript object is what really makes it all work. This allows you to pass many pieces of data back. You simply pull them out of the JS object once you’re back in the HTML page. You may even pass several JS objects inside each other.In this case I’m passing three parameters in one JS object.
paramsObj.datais the chart data, which came as a nested object which is formatted according to the Google Visualization API. I had to useeval()again to set the nested JS object as a separate variable, or it doesn’t pass to theloadChart()function correctly.paramsObj.titleandparamsObj.xLabelare simply strings.