|
How to pump ImageMap in real-time chart in JSP page? |
Posted by Henry Choi on May-02-2007 01:01 |
|
Hello support,
Thank you in advance for your prompt and helpful remarks. I was able to build a nice real-time dashboard in just couple of days of prototyping. Everything is working well with the dashboard, but I hit a snag. Following your realtimechart.jsp example, I have this following interactions between the 2 JSP pages:
+- TLGN.jsp -----------------+ +- TLGN_chart.jsp -----------------+
| when timer expires | | |
| JsChartViewer.get() | | |
| .streamUpdate(); -----------+----+--> chart.getHTMLImageMap(); |
| | | viewer.setImageMap( |
| | | viewer.makeDelayedMap()); |
| <IMG id="..." SRC= <-------+-----+--- viewer.streamChart(response, |
| "TLGN_chart.jsp? | | chart.makeChart2()); |
| chartId=TLGN_chart" | | |
| USEMAP="TLGN_ChartMap">| | |
| <MAP | +----------------------------------+
| NAME="TLGN_ChartMap"> |
| myImageMap |
| </MAP> |
+----------------------------+
As you can see, I need to figure out how to set myImageMap to the correct value Iin TLGN.jsp. I am encouraged that one of the functionalities of the JsChartViewer is:
"Provide support for delayed and compressed image map." according to the documentation, and would like to know to use JsChartViewer to get the ImageMap sent by the viewer in TLGN_chart.jsp.
With appreciation,
Henry Choi |
Re: How to pump ImageMap in real-time chart in JSP page? |
Posted by Peter Kwan on May-02-2007 03:48 |
|
Hi Henry,
The streamChart method is designed for efficient update of the charts, in which only 1 HTTP connection is used for each chart update. However, due to the limitation of HTTP, a single HTTP connection can only transfer either the chart image, or the chart image map, but not both. So in the streamChart method, only the chart image is updated, and there is no image map for the chart.
If you need image maps for the charts, you may use "partialUpdate" instead. This is the method used in the "Zoomable and Scrollable Charts". However, instead of updating the chart when the user scrolls the chart, you can use a Javascript timer to periodic trigger a partial update.
I have attached an example for your reference.
Hope this can help.
Regards
Peter Kwan
realtimedemo2.jsp |
---|
<%@page import="ChartDirector.*" %>
<%@page import="java.util.*" %>
<%!
//
// Data to draw the chart. In this demo, the data buffer will be filled by a random
// data generator. In real life, the data is probably stored in a buffer (eg. a
// database table, a text file, or some global memory) and updated by other means.
//
private void drawChart(WebChartViewer viewer)
{
// We use a data buffer to emulate the last 240 samples.
int sampleSize = 240;
double[] dataSeries1 = new double[sampleSize];
double[] dataSeries2 = new double[sampleSize];
double[] dataSeries3 = new double[sampleSize];
Date[] timeStamps = new Date[sampleSize];
// Our pseudo random number generator
double firstDate = new Date().getTime() / 1000 - timeStamps.length;
for (int i = 0; i < timeStamps.length; ++i) {
double p = firstDate + i;
timeStamps[i] = new Date((long)p * 1000);
dataSeries1[i] = Math.cos(p * 7 * 18463) * 10 + 1 / (Math.cos(p) * Math.cos(p) +
0.01) + 20;
dataSeries2[i] = 100 * Math.sin(p / 27.7) * Math.sin(p / 10.1) + 150;
dataSeries3[i] = 100 * Math.cos(p / 6.7) * Math.cos(p / 11.9) + 150;
}
// Create an XYChart object 600 x 270 pixels in size, with light grey (f4f4f4)
// background, black (000000) border, 1 pixel raised effect, and with a rounded
// frame.
XYChart c = new XYChart(600, 270, 0xf4f4f4, 0x000000, 0);
c.setRoundedFrame();
// Set the plotarea at (55, 62) and of size 520 x 175 pixels. Use white (ffffff)
// background. Enable both horizontal and vertical grids by setting their colors to
// grey (cccccc). Set clipping mode to clip the data lines to the plot area.
c.setPlotArea(55, 62, 520, 175, 0xffffff, -1, -1, 0xcccccc, 0xcccccc);
c.setClipping();
// Add a title to the chart using 15 pts Times New Roman Bold Italic font, with a
// light grey (dddddd) background, black (000000) border, and a glass like raised
// effect.
c.addTitle("Zooming and Scrolling Demonstration", "Times New Roman Bold Italic", 15
).setBackground(0xdddddd, 0x000000, Chart.glassEffect());
// Add a legend box at the top of the plot area with 9pts Arial Bold font. We set the
// legend box to the same width as the plot area and use grid layout (as opposed to
// flow or top/down layout). This distributes the 3 legend icons evenly on top of the
// plot area.
LegendBox b = c.addLegend2(55, 33, 3, "Arial Bold", 9);
b.setBackground(Chart.Transparent, Chart.Transparent);
b.setWidth(520);
// Configure the y-axis with a 10pts Arial Bold axis title
c.yAxis().setTitle("Price (USD)", "Arial Bold", 10);
// Configure the x-axis to auto-scale with at least 75 pixels between major tick and
// 15 pixels between minor ticks. This shows more minor grid lines on the chart.
c.xAxis().setTickDensity(75, 15);
// Set the axes width to 2 pixels
c.xAxis().setWidth(2);
c.yAxis().setWidth(2);
// Set the x-axis label format
c.xAxis().setLabelFormat("{value|hh:nn:ss}");
// Create a line layer to plot the lines
LineLayer layer = c.addLineLayer2();
// The x-coordinates are the timeStamps.
layer.setXData(timeStamps);
// The 3 data series are used to draw 3 lines. Here we put the latest data values as
// part of the data set name, so you can see them updated in the legend box.
layer.addDataSet(dataSeries1, 0xff0000, c.formatValue(dataSeries1[dataSeries1.length
- 1], "Software: <*bgColor=FFCCCC*> {value|2} "));
layer.addDataSet(dataSeries2, 0x00cc00, c.formatValue(dataSeries2[dataSeries2.length
- 1], "Hardware: <*bgColor=CCFFCC*> {value|2} "));
layer.addDataSet(dataSeries3, 0x0000ff, c.formatValue(dataSeries3[dataSeries3.length
- 1], "Services: <*bgColor=CCCCFF*> {value|2} "));
// Create the image and save it in a temporary location
String chartQuery = c.makeSession(viewer.getRequest(), viewer.getId());
String imageMap = c.getHTMLImageMap("", "", "title='[{dataSetName}] {x|hh:nn:ss}: {value|2}'");
// Set the chart URL, image map to the viewer
viewer.setImageUrl("getchart.jsp?" + chartQuery);
viewer.setImageMap(imageMap);
}
%>
<%
// Create the WebChartViewer object
WebChartViewer viewer = new WebChartViewer(request, "ChartImage1");
drawChart(viewer);
if (viewer.isPartialUpdateRequest()) {
// Since it is a partial update, there is no need to output the entire web page. We stream the
// chart and then terminate the script immediately.
out.clear();
viewer.partialUpdateChart(response);
return;
}
%>
<html>
<head>
<title>ChartDirector Realtime Chart Demonstration</title>
<script language="Javascript" src="cdjcv.js"></script>
</head>
<body leftMargin="0" topMargin="0">
<table cellSpacing="0" cellPadding="0" border="0">
<tr>
<td align="right" bgColor="#000088" colSpan="2">
<div style="padding-bottom:2px; padding-right:3px; font-weight:bold; font-size:10pt; font-style:italic; font-family:Arial;">
<A style="color:#FFFF00; text-decoration:none" href="http://www.advsofteng.com/">Advanced Software Engineering</a>
</div>
</td>
</tr>
<tr vAlign="top">
<td style="border-left:black 1px solid; border-right:black 1px solid; border-bottom:black 1px solid;" width="150" bgColor="#c0c0ff">
<br><br>
<div style="padding:10px; font-size:9pt; font-family:Verdana">
<b>Update Period</b><br>
<select id="UpdatePeriod" style="width:130px">
<option Value="5">5 seconds</option>
<option Value="10" Selected>10 seconds</option>
<option Value="20">20 seconds</option>
<option Value="30">30 seconds</option>
<option Value="60">60 seconds</option>
</select>
</div>
<div style="padding:10px; font-size:9pt; font-family:Verdana">
<b>Time Remaining</b><br>
<div style="width:130px; border:#888888 1px inset;">
<div style="margin:3px" id="TimeRemaining"> </div>
</div>
</div>
</td>
<td>
<div style="font-weight:bold; font-size:20pt; margin:5px 0px 0px 5px; font-family:Arial">
ChartDirector Real-Time Chart Demonstration
</div>
<hr color="#000088">
<div style="padding:0px 5px 0px 10px">
<!-- ****** Here is the chart image ****** -->
<%=viewer.renderHTML(response)%>
</div>
</td>
</tr>
</table>
<script>
// The followings is executed once every second
function updateDisplay()
{
// Utility to get an object by id that works with most browsers
var getObj = function(id) { return document.getElementById ? document.getElementById(id) : document.all[id]; }
// Get the configured update period
var updatePeriodObj = getObj("UpdatePeriod");
var updatePeriod = parseInt(updatePeriodObj.value);
// Subtract 1 second for the remaining time - reload the counter if remaining time is 0
if (!updatePeriodObj.timeLeft || (updatePeriodObj.timeLeft <= 0))
updatePeriodObj.timeLeft = updatePeriod - 1;
else
updatePeriodObj.timeLeft = Math.min(updatePeriod, updatePeriodObj.timeLeft) - 1;
// Update the chart if configured time has elasped
if ((updatePeriodObj.timeLeft <= 0) && window.JsChartViewer)
JsChartViewer.get('ChartImage1').partialUpdate();
// Update the display to show remaining time
getObj("TimeRemaining").innerHTML = updatePeriodObj.timeLeft + ((updatePeriodObj.timeLeft > 1) ? " seconds" : " second");
}
window.setInterval("updateDisplay()", 1000);
</script>
</body>
</html>
|
| |
Re: How to pump ImageMap in real-time chart in JSP page? |
Posted by Henry Choi on May-03-2007 01:06 |
|
Thank you Peter for the quick and helpful reply. Can you please help me with the next problem? I promise you it will be worth your while; if this works out, we will not only use this for a prototype we are building for our customer (major fortune 100 company), but might use it ourselves--there is definitely money at the end of the tunnel.
On the positive note, JsChartViewer.partialUpdate() and WebChartViewer.renderHTML(response) does seem to work!
But there seems to be a problem when I have more than 1 such JSP pages included in my master page. 1 image shows up in another IMG! A graph (attached) of the index.jsp page will hopefully clarify the situation, where:
* Top 10 IP Summary is being updated from TopIP.jsp using partialUpdate()
* Top Entry Summary is being updated from TopEntry.jsp using streamUpdate()
* TL/GN/LB Summary is being updated from TLGNLB.jsp using partialUpdate()
All 3 jsp pages are included into the index.jsp using jsp:include tag (e.g. <jsp:include page="TLGNLB.jsp" flush="true" />).
As you can see from the screenshot, TL/GN/LB Summary is actually showing the IMG for TopIP.jsp. But an even strange are the following:
* At the very beginning (when I first open the index.jsp page), I *do* see the correct image from TLGNLB.jsp--but only once.
* Sometimes, TLGNLB.jsp is shown in Top 10 IP Summary. So the mix-up goes both ways I guess.
* Top Entry Summary always the right picture from TopEntry.jsp. In fact, when I had multiple IMGs for different parts of my dashboard yesterday, all the images updated correctly--other than the lack of MAP data.
Not being a JSP expert, I don't understand what is going on. Viewing the HTML source, it would seem that everything is in order, as can be seen in following, where the arguments to getchart.jsp are *different* for the 2 IMGs concerned. I think it's because the 2 respective JSP pages create separate viewers (new WebChartViewer(request, "TopIP_ChartImage") vs. new WebChartViewer(request, "TLGNLB_ChartImage").
* in the HTML source for Top 10 IP summary:
...
<div>
<!-- ****** Here is the chart image ****** -->
<input type='hidden' id='TopIP_ChartImage_JsChartViewerState'
name='TopIP_ChartImage_JsChartViewerState' value='' /><input type='hidden'
id='TopIP_ChartImage_callBackURL' name='TopIP_ChartImage_callBackURL'
value='/WF_ISG_demo/;jsessionid=27AD2B65464B614333C3A5FFD378C34D?cdLoopBack=1' /><map
id='map_TopIP_ChartImage' name='map_TopIP_ChartImage'>...map data...</map><img id='TopIP_ChartImage'
src='getchart.jsp;jsessionid=27AD2B65464B614333C3A5FFD378C34D?
img=TopIP_ChartImage&id=27AD2B65464B614333C3A5FFD378C34D_1' border='0'
usemap='#map_TopIP_ChartImage'>
</div>
* in the HTML source for TL/GN/LB Summay,
<div>
<!-- ****** Here is the chart image ****** -->
<input type='hidden' id='TLGNLB_ChartImage_JsChartViewerState'
name='TLGNLB_ChartImage_JsChartViewerState' value='' /><input type='hidden'
id='TLGNLB_ChartImage_callBackURL' name='TLGNLB_ChartImage_callBackURL'
value='/WF_ISG_demo/;jsessionid=27AD2B65464B614333C3A5FFD378C34D?cdLoopBack=1' /><map
id='map_TLGNLB_ChartImage' name='map_TLGNLB_ChartImage'>...map data...</map><img id='TLGNLB_ChartImage'
src='getchart.jsp;jsessionid=27AD2B65464B614333C3A5FFD378C34D?
img=TLGNLB_ChartImage&id=27AD2B65464B614333C3A5FFD378C34D_3' border='0'
usemap='#map_TLGNLB_ChartImage'>
</div>
With appreciation,
Henry Choi
|
Re: How to pump ImageMap in real-time chart in JSP page? |
Posted by Peter Kwan on May-03-2007 03:43 |
|
Hi Henry,
The issue is related to the code that processes the partial update (AJAX update).
In the original sample code, it just handles the AJAX requests and sends back updated charts, without checking if the AJAX requests are really for that particular WebChartViewer. It is because in the original code, there is only 1 WebChartViewer, so there is no ambiguity.
In your case, the "index.jsp" includes three jsp. If the structure of the original sample code is used, then the first jsp loaded will handles the AJAX requests and sends back its chart. So all AJAX chart updates results in the first chart ("TopIP.jsp") being sent back.
In the original sample code, the code that checks for partial updates is as follows:
// Create the WebChartViewer object
WebChartViewer viewer = new WebChartViewer(request, "ChartImage1");
drawChart(viewer);
if (viewer.isPartialUpdateRequest()) {
// Since it is a partial update, there is no need to output the entire web page. We stream the
// chart and then terminate the script immediately.
out.clear();
viewer.partialUpdateChart(response);
return;
}
For multiple WebChartViewers, it needs to be modified to:
// Create the WebChartViewer object
WebChartViewer viewer = new WebChartViewer(request, "ChartImage1");
if (viewer.isPartialUpdateRequest()) {
if (viewer.getSenderClientId().equals(viewer.getId())) {
drawChart(viewer);
// Since it is a partial update, there is no need to output the entire web page. We stream the
// chart and then terminate the script immediately.
out.clear();
viewer.partialUpdateChart(response);
return;
}
}
else
drawChart(viewer);
The above code adds an additional check to ensure the partial update request is really for the intended WebChartViewer before drawing the chart and sending the results back.
I have attached a complete example with 2 charts included for your reference.
Hope this can help.
Regards
Peter Kwan
|
Re: How to pump ImageMap in real-time chart in JSP page? |
Posted by Henry Choi on May-04-2007 03:22 |
|
Thanks Peter, Your support is top-notch! |
|