/**
* Copyright (C) 2013 Arman Gal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.clevermore.monitor.client.widgets;
import java.util.List;
import org.clevermore.monitor.shared.ChartFeed;
import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.googlecode.gwt.charts.client.ChartLoader;
import com.googlecode.gwt.charts.client.ChartPackage;
import com.googlecode.gwt.charts.client.ColumnType;
import com.googlecode.gwt.charts.client.DataTable;
import com.googlecode.gwt.charts.client.corechart.LineChart;
import com.googlecode.gwt.charts.client.corechart.LineChartOptions;
import com.googlecode.gwt.charts.client.options.CurveType;
import com.googlecode.gwt.charts.client.options.HAxis;
import com.googlecode.gwt.charts.client.options.VAxis;
public class MonitoringDynamicLinesChart<V extends Number, X extends Number>
extends Composite {
private CurveType curveType = CurveType.FUNCTION;
private LineChart chart;
private FlowPanel fp = new FlowPanel();
private String title;
private String yColumnName;
private String xColumnname;
private ChartFeed<V, X> chartFeeds;
private boolean lastRowAsColumn;
private List<ILineType> lineTypes;
private boolean initilized = false;
public MonitoringDynamicLinesChart(CurveType curveType, String yColumnName, String xColumnname, String title) {
this(yColumnName, xColumnname, title);
this.curveType = curveType;
}
public MonitoringDynamicLinesChart(String yColumnName, String xColumnname, String title) {
this.yColumnName = yColumnName;
this.xColumnname = xColumnname;
this.title = title;
ChartLoader chartLoader = new ChartLoader(ChartPackage.CORECHART);
chartLoader.loadApi(new Runnable() {
@Override
public void run() {
try {
// Create and attach the chart
chart = new LineChart();
chart.setHeight("100%");
fp.add(chart);
initilized = true;
if (chartFeeds != null) {
updateChart(lineTypes, chartFeeds, lastRowAsColumn);
}
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
}
});
initWidget(fp);
}
public void updateChart(List<ILineType> lineTypes, ChartFeed<V, X> chartFeeds) {
updateChart(lineTypes, chartFeeds, false);
}
public void updateChart(CurveType curveType, List<ILineType> lineTypes, ChartFeed<V, X> chartFeeds, boolean hasXLineValues) {
this.curveType = curveType;
updateChart(lineTypes, chartFeeds, hasXLineValues);
}
/**
* @param chartFeeds
* @param hasXLineValues - meaning the the last row in the chartFeeds includes X line values (usually
* time)
*/
public void updateChart(List<ILineType> lineTypes, ChartFeed<V, X> chartFeeds, boolean hasXLineValues) {
try {
if (!initilized) {
this.chartFeeds = chartFeeds;
this.lastRowAsColumn = hasXLineValues;
this.lineTypes = lineTypes;
return;
}
// Prepare the data
DataTable dataTable = DataTable.create();
dataTable.addColumn(ColumnType.STRING, xColumnname); // 0 index
// adding lines
for (int i = 0; i < lineTypes.size(); i++) {
dataTable.addColumn(lineTypes.get(i).getColumnType(), lineTypes.get(i).getName());
}
dataTable.addRows(chartFeeds.getValuesLenght());
Log.debug("Adding:" + chartFeeds.getValuesLenght() + " rows to chart");
if (hasXLineValues) {
for (int i = 0; i < chartFeeds.getValuesLenght(); i++) {
dataTable.setValue(i, 0, String.valueOf(chartFeeds.getXLineValues()[i]));
}
} else {
// create X values on chart
for (int i = 0; i < chartFeeds.getValuesLenght(); i++) {
dataTable.setValue(i, 0, String.valueOf(i));
}
}
for (int i = 0; i < lineTypes.size(); i++) {
drawLine(chartFeeds, lineTypes.get(i), dataTable);
}
// Set options
LineChartOptions options = LineChartOptions.create();
options.setBackgroundColor("#f0f0f0");
options.setFontName("Tahoma");
options.setTitle(title);
options.setHAxis(HAxis.create(xColumnname));
options.setVAxis(VAxis.create(yColumnName));
options.setCurveType(curveType);
String[] color = new String[lineTypes.size()];
for (int i = 0; i < lineTypes.size(); i++) {
color[i] = lineTypes.get(i).getLineColor();
}
options.setColors(color);
// Draw the chart
chart.draw(dataTable, options);
} catch (Exception e) {
Log.error("MonitoringLineChart.update:, " + e.getMessage(), e);
}
}
public void clean() {
try {
chart.clearChart();
} catch (Exception e) {
// Log.error("MonitoringLineChart.clean:, " + e.getMessage(), e);
}
}
private void drawLine(ChartFeed<V, X> chartFeeds, ILineType lineType, DataTable dataTable) {
@SuppressWarnings("unchecked")
V prevNormalValue = (V) new Integer(Integer.MIN_VALUE);
Log.debug("Adding line:" + lineType.getName() + ":" + lineType.getIndex() + " with values:" + chartFeeds.getValuesLenght());
// Log.debug("Data:" + Arrays.toString(chartFeeds.getValues()[lineType.getIndex()]));
for (int i = 0; i < chartFeeds.getValuesLenght(); i++) {
V value = chartFeeds.getValues(lineType.getIndex(), i);
if (value.intValue() == Integer.MIN_VALUE) {
// this case means that this line do not have valid value for current "period" or "Y"
if (prevNormalValue.intValue() != Integer.MIN_VALUE) {
// draw previous value is case it's valid one, we're OK to start drawing the line from a
// middle of the chart
dataTable.setValue(i, lineType.getIndex() + 1, prevNormalValue.doubleValue());
}
continue;
}
prevNormalValue = value;
dataTable.setValue(i, lineType.getIndex() + 1, value.doubleValue());
}
}
@Override
public void setTitle(String title) {
this.title = title;
}
}