package com.googlecode.gchart.gchartdemoapp.client; import com.google.gwt.user.client.*; import com.google.gwt.user.client.ui.*; import com.googlecode.gchart.client.GChart; import com.googlecode.gchart.client.HoverUpdateable; /** Combination chart containing pie, line, and bar-based curves. *
*
* Also illustrates use of single-sided point selection brushes,
* fixed-chart-location hover annotations, and the use of a simple list
* box hover widget for quickly changing a single chart property.
*
*/
public class GChartExample11 extends GChart {
final double INITIAL_PRICE = 100;
final double MAX_MONTHLY_RELATIVE_CHANGE = 0.2;
final int N_FORCASTED_MONTHS = 13;
final int MIN = 0;
final int MAX = 1;
final int AVG = 2;
final int STD = 3; // estimated standard deviation
final int N_STATS = 4;
final int PRICE = 2; // curve id of simple price curve
final int BDIF = 3; // curve id of backward difference curve
double[] prices = new double[N_FORCASTED_MONTHS];
double[] stats = new double[N_STATS];
String[] statLabels = {"min: ", "max: ", "avg: ", "std: ",};
String[] shortStatLabels = {"min", "max", "avg", "std",};
final String SOURCE_CODE_LINK =
"Source code";
final Button updateButton = new Button("Update");
final Label updateTimeMsg = new Label();
HoverUpdateableListBox[] hoverList = {new HoverUpdateableListBox(MIN),
new HoverUpdateableListBox(MAX)};
int[] iStat = {MIN, MAX}; // ids of stats mapped to the two pie slices
void updateStatSlices(int iStat0, int iStat1) {
iStat[0] = iStat0;
iStat[1] = iStat1;
updateStatSlices();
}
void updateStatSlices() {
getCurve(0).getSymbol().setPieSliceSize(
stats[iStat[0]]/(stats[iStat[0]]+stats[iStat[1]]));
getCurve(1).getSymbol().setPieSliceSize(
stats[iStat[1]]/(stats[iStat[0]]+stats[iStat[1]]));
getCurve(0).getPoint().setAnnotationText(
shortStatLabels[iStat[0]]);
getCurve(1).getPoint().setAnnotationText(
shortStatLabels[iStat[1]]);
}
// pop-up-on-hover-over list box that shows, lets user
// switch, statistic mapped to each pie slice
class HoverUpdateableListBox extends ListBox
implements HoverUpdateable {
HoverUpdateableListBox(int iStat) {
for (int i = 0; i < N_STATS; i++)
addItem(statLabels[i] + stats[i]);
setItemSelected(iStat,true);
setVisibleItemCount(stats.length);
addChangeListener(new ChangeListener() {
public void onChange(Widget sender) {
updateStatSlices(hoverList[0].getSelectedIndex(),
hoverList[1].getSelectedIndex());
update(TouchedPointUpdateOption.TOUCHED_POINT_LOCKED);
}
});
}
// The two HoverUpdateable interface methods follow
public void hoverCleanup(Curve.Point hoveredAwayFrom) {}
public void hoverUpdate(Curve.Point hoveredOver) {
int iCurve = getCurveIndex(getTouchedCurve());
for (int i = 0; i < N_STATS; i++) // update list text
setItemText(i, statLabels[i] +
getYAxis().formatAsTickLabel(Math.round(stats[i])));
// highlight statistic pie slice is now displaying
hoverList[iCurve].setSelectedIndex(iStat[iCurve]);
}
}
// Returns Grid with code link, update button, & timing message
// shown at the bottom of Client-side GChart live-demo
// charts (just demo infrastructure, not GChart-specific code)
private Grid getDemoFootnotes(String sourceCodeLink,
Widget updateWidget,
Label updateTimeMsg) {
HTML sourceCode = new HTML(sourceCodeLink);
Widget[] w = {sourceCode, updateWidget, updateTimeMsg};
String[] wWidth = {"40%", "20%", "40%"};
Grid result = new Grid(1, w.length);
for (int i = 0; i < w.length; i++) {
result.setWidget(0, i, w[i]);
result.getCellFormatter().setWidth(0,i, wWidth[i]);
result.getCellFormatter().setHorizontalAlignment(0,i,
HasHorizontalAlignment.ALIGN_CENTER);
}
result.setWidth(getXChartSizeDecorated()+"px");
return result;
}
// updates the chart with results of a new oil price simulation
private void updateChart() {
double sum = INITIAL_PRICE; // simple sum of all prices
double ssq = INITIAL_PRICE*INITIAL_PRICE; // sum of squares of prices
stats[MIN] = INITIAL_PRICE;
stats[MAX] = INITIAL_PRICE;
prices[0] = INITIAL_PRICE;
for (int i=1; i < N_FORCASTED_MONTHS; i++) {
prices[i] = prices[i-1] *
(1 + MAX_MONTHLY_RELATIVE_CHANGE*(2*Math.random()-1));
stats[MIN] = Math.min(stats[MIN], prices[i]);
stats[MAX] = Math.max(stats[MAX], prices[i]);
sum += prices[i];
ssq += prices[i]*prices[i];
}
stats[AVG] = sum/N_FORCASTED_MONTHS;
// use "average of squares minus square of average"
// formula for variance to get standard deviation.
stats[STD] = Math.sqrt(ssq/N_FORCASTED_MONTHS -
stats[AVG]*stats[AVG]);
updateStatSlices(); // update pie slices to reflect new stats
// update backward-price-difference and price curves
getCurve(BDIF).clearPoints();
getCurve(PRICE).clearPoints();
for (int i = 0; i < N_FORCASTED_MONTHS; i++) {
getCurve(BDIF).addPoint(i, (i == 0)?0:(prices[i]-prices[i-1]));
getCurve(PRICE).addPoint(i,prices[i]);
if (prices[i]!=stats[MIN] && prices[i]!=stats[MAX]) {
//no min/max;
getCurve(PRICE).getPoint().setAnnotationText(null); //no label
}
else {
// label point to indicate it's at a min or max price
getCurve(PRICE).getPoint().setAnnotationFontSize(10);
getCurve(PRICE).getPoint().setAnnotationFontWeight("bold");
if (prices[i]==stats[MIN]) {
getCurve(PRICE).getPoint().setAnnotationLocation(
AnnotationLocation.SOUTH);
getCurve(PRICE).getPoint().setAnnotationText(shortStatLabels[MIN]);
getCurve(PRICE).getPoint().setAnnotationFontColor("blue");
}
else {
getCurve(PRICE).getPoint().setAnnotationLocation(
AnnotationLocation.NORTH);
getCurve(PRICE).getPoint().setAnnotationText(shortStatLabels[MAX]);
getCurve(PRICE).getPoint().setAnnotationFontColor("blue");
}
}
}
update();
}
GChartExample11() {
long t0 = System.currentTimeMillis();
// misc chart configuration
setChartSize(400, 250);
setWidth("100%");
setPlotAreaBackgroundColor("#CCC");
setLegendBackgroundColor(getPlotAreaBackgroundColor());
setGridColor("#EEE");
// convenience methods; these properties could also have been defined
// via CSS. See the javadoc comment for GChart.USE_CSS for more info.
setBackgroundColor("#DDF");
setBorderColor("black");
setBorderWidth("1px");
setBorderStyle("outset");
setFontFamily("Veranda, Arial, sans-serif");
// title and footnotes (w. update button)
setChartTitle(
"Estimated Future Oil Prices " +
"
" +
"All results are pseudo-random. " +
"Randomize fully before you invest.
" +
"");
setChartTitleThickness(60);
setLegendVisible(false);
final Button updateButton = new Button(
"Update");
updateButton.setTitle(
"Click for new totally unbiased, totally random, estimates.");
updateButton.addClickListener(new ClickListener() {
public void onClick(Widget w) {
long t0 = System.currentTimeMillis();
updateChart();
long t1 = System.currentTimeMillis();
updateTimeMsg.setText((t1-t0) + "ms");
updateButton.setFocus(true);
}
});
// x-axis config
getXAxis().setAxisLabel(
"time (months from now)");
getXAxis().setAxisLabelThickness(20);
getXAxis().setTickCount(13);
getXAxis().setTicksPerLabel(2);
getXAxis().setAxisMin(0);
getXAxis().setAxisMax(N_FORCASTED_MONTHS-1);
getXAxis().setHasGridlines(true);
// y-axis config
getYAxis().setAxisLabel(
"