GWT dynamic width of linechart - gwt

I have putted below code line chart visualization.can any one tell me how to set the dynamic widht in linechart of gwt vissualization graph?
options.setWidth(1000); i want the instead of 1000 some dynamic value.
enter code here
public class CPUChart extends VerticalPanel{
private LineChart lineChart;
private DataTable data;
public CPUChart(final CPUChartDataQueue cpuChartDataQueue) {
VisualizationUtils.loadVisualizationApi(new Runnable() {
public void run() {
setLayoutData(new FitLayout());
lineChart = new LineChart(createTable(cpuChartDataQueue), createOptions("CPU Chart"));
add(lineChart);
}}, LineChart.PACKAGE);
}
private Options createOptions(String title) {
Options options = Options.create();
**options.setWidth(1000);
options.setHeight(300);**
options.setTitleFontSize(11);
options.setShowCategories(true);
options.setLegend(LegendPosition.BOTTOM);
options.setTitle(title);
options.setSmoothLine(true);
options.setAxisFontSize(12);
options.setColors(Color3D.create("#A4C735", "#4F7512"),Color3D.create("#FF4C4C", "#FF0303"));
options.setMin(0);
options.setMax(100);
options.setTitleY("Percentage(%)");
options.setTitleX("Time");
return options;
}
private AbstractDataTable createTable(CPUChartDataQueue cpuChartDataQueue) {
DataTable data = DataTable.create();
data.addColumn(ColumnType.STRING, "Time");
data.addColumn(ColumnType.NUMBER, "CPU Usage Percentage");
Queue<CPUChartData> chartDatas = cpuChartDataQueue.getQue();
if(chartDatas!=null && chartDatas.size()>0){
data.addRows(chartDatas.size());
int i=0;
for (CPUChartData chartData : chartDatas) {
data.setValue(i, 0, chartData.getLable());
data.setValue(i, 1, Integer.parseInt(chartData.getValue()));
i++;
}
}
return data;
}
public void refreshChart(CPUChartDataQueue cpuChartDataQueue){
data = DataTable.create();
data.addColumn(ColumnType.STRING, "Time");
data.addColumn(ColumnType.NUMBER, "CPU Usage Percentage");
Queue<CPUChartData> chartDatas = cpuChartDataQueue.getQue();
if(chartDatas!=null && chartDatas.size()>0){
data.addRows(chartDatas.size());
int i=0;
for (CPUChartData chartData : chartDatas) {
data.setValue(i, 0, chartData.getLable());
data.setValue(i, 1, Integer.parseInt(chartData.getValue()));
i++;
}
}
lineChart.draw(data,createOptions("CPU Chart"));
}
}

Most Google visualization charts require explicit sizes in pixel. Only some FLASH charts support percentage dimensions.
A workaround is to add a onResize Handler to the window and redraw/recreate the chart whenever the browser window is resized.

Related

how to add an onclick event in an implementation of AbstractHasData in gwt

how to add an onclick event in an implementation of AbstractHasData. I think I have to add CellPreviewEvent but Im having diffculties doing that. Please let me know if my approach is correct and how to add CellPreviewEvent.
public class TLayout extends AbstractHasData<Summary> {
private LayoutPanel main;
private ScrollPanel scroller;
private FlowPanel contents;
private ListDataProvider<Summary> dataProvider = new ListDataProvider<Summary>();
public TLayout(int pageSize,
ListDataProvider<Summary> dataProvider) {
super(new LayoutPanel(), pageSize, dataProvider.getKeyProvider());
this.dataProvider = dataProvider;
main = (LayoutPanel) getWidget();
main.addStyleName("TLayout");
contents = new FlowPanel();
scroller = new ScrollPanel(contents);
main.add( scroller );
scroller.addStyleName("scroller" );
contents.addStyleName("contents");
main.setSize("100%", "100%");
main.setWidgetLeftRight(scroller, 0, Unit.PCT, 0, Unit.PCT);
main.setWidgetTopBottom(scroller, 0, Unit.PCT, 0, Unit.PCT);
}
#Override
protected void renderRowValues(SafeHtmlBuilder sb,
List<Summary > values, int start,
SelectionModel<? super Summary > selectionModel)
throws UnsupportedOperationException {
// TODO Auto-generated method stub
Log.debug( "TLayout.renderRowValues() ENTER" );
for (Summary summary : values) {
sb.appendHtmlConstant(createCard( summary ));
}
}
private String createCard(Summary summary ) {
StringBuilder builder= new StringBuilder();
builder.append("<div class='summary'>");
....
.....
return builder.toString();
}
The easiest way is to use a SelectionModel. You can add a SelectionModel to the abstract has data that will handle selection of your summary class.
private final SingleSelectionModel<Summary> summarySelectionModel = new SingleSelectionModel<Summary>() {
{
addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
Summary summary = getSelectedObject();
if (summary != null) {
// do something
}
}
});
}
};
tlLayout.addSelectionModel(summarySelectionModel);

Display in a ColumnChart the value inside the column (not only when hover)

I have a GWT application which display severals chart with gwt-visualization.
I want in my ColumnChart the value of the column inside it.
In the official documentation, we can see that with DataView we can add the value inside a column:
https://developers.google.com/chart/interactive/docs/gallery/columnchart
(please see the type of graph that i want before "This is a little more complicated than it should be, because we create a DataView to specify the annotation for each column.")
Here my actual code wich display the value only when we hover the column:
ColumnChart col = new ColumnChart(createColTable(), createColOptions());
fp.add(col);
private AbstractDataTable createColTable() {
int maxNbLines = 5;
DataTable data = DataTable.create();
data.addColumn(ColumnType.STRING, messages.user());
data.addColumn(ColumnType.NUMBER, messages.nbMsg());
data.addColumn(ColumnType.NUMBER, messages.nbTot());
data.addRows(maxNbLines);
if (this.getMetrics().size() > 0) {
int j = 0;
for (java.util.Map.Entry<String,UIMetricsBean> entry :
this.getDayMetrics().entrySet()) {
String key = entry.getKey();
UIMetricsBean value = entry.getValue();
data.setValue(j, 0, key);
data.setValue(j, 1, value.getNbTotal());
data.setValue(j, 2, value.getNbBad());
j++;
if(j >= maxNbLines) {
break;
}
}
}
return data;
}
private Options createColOptions() {
TextStyle titleTextStyle = TextStyle.create();
titleTextStyle.setFontSize(18);
titleTextStyle.setColor(COLOR_RED);
Options options = Options.create();
options.setWidth(720);
options.setHeight(350);
options.setTitle(messages.tot());
options.setColors(COLOR_GRAY, COLOR_RED);
options.setBackgroundColor(COLOR_BACKGROUND_GRAY);
TextStyle axisTextStyle = TextStyle.create();
axisTextStyle.setFontSize(8);
HorizontalAxisOptions hAxisOption = HorizontalAxisOptions.create();
hAxisOption.setTextStyle(axisTextStyle);
options.setHAxisOptions(hAxisOption);
options.setTitleTextStyle(titleTextStyle);
return options;
}
Do you know how i can display the value of the column inside the column?
Thanks!
You can achieve this using JSNI and annotation. Here is a working example. You still need to pass your data as an Array to JSNI.
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.visualization.client.AbstractDataTable;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.corechart.BarChart;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class TestChart implements EntryPoint {
public void onModuleLoad() {
final FlowPanel flowPanel = new FlowPanel();
Panel panel = RootPanel.get();
panel.add(flowPanel);
Runnable onLoadCallback = new Runnable() {
public void run() {
BarChart bar = new BarChart(createTable(), createOptions());
flowPanel.add(bar);
}
};
VisualizationUtils.loadVisualizationApi(onLoadCallback, BarChart.PACKAGE);
}
private AbstractDataTable createTable() {
DataTable data = createTemplate();
return data;
}
private Options createOptions() {
Options options = getNativeOptions();
//set other options
return options;
}
private native Options getNativeOptions() /*-{
var options = #com.google.gwt.visualization.client.visualizations.corechart.Options::create()();
options = {
fontName : 'Calibri',
fontSize : 12,
width: 600,
height: 400,
displayAnnotations: true,
orientation : 'horizontal',
legend: { position: "none" },
};
return options;
}-*/;
private native DataTable createTemplate() /*-{
var data = $wnd.google.visualization.arrayToDataTable([
['Element', 'Density', { role: 'style' }, { role: 'annotation' } ],
['Copper', 8.94, '#b87333', '8.94' ],
['Silver', 10.49, 'silver', '10.49' ],
['Gold', 19.30, 'gold', '19.30' ],
['Platinum', 21.45, 'color: #e5e4e2', '21.45' ]
]);
return data;
}-*/;
}
The result
Can be done easily as shown below using visualization API.
Write JSNI method as follows:
private native DataTable addAnnotationColumn(DataTable data) /*-{
data.addColumn({type: 'string', role: 'annotation'});
return data;
}-*/;
Create a DataTable:
DataTable dataTable = DataTable.create();
addAnnotationColumn(dataTable);
Set the Data:
dataTable.setValue(row, column, "Your text over here");

Is there a "correct" way to add/remove a PieChart?

I have an MVP GWT 2.5.1 app using version 1.1.1 of gwt-visualization. My view has two Buttons and a VerticalPanel (accessed by the presenter as display.getPanel()). One button adds a PieChart to the VerticalPanel, the the other removes it. The presenter holds the PieChart reference as a Widget so that it knows when it has been added/removed. It is initialized to null.
I checked chrome's dev tools to ensure that the add/remove code wasn't creating a DOM leak. But after the PieChart was removed, its elements were left behind in a detached DOM tree, all color coded red. When I tried the same add/remove code with a Label instead of a PieChart, no detached DOM tree remained after removal.
My questions is: am I doing something wrong when either adding or removing the PieChart? Perhaps gwt-visualization has some other method of handling this that I am not aware of, but my google-fu is unable to produce an answer.
The presenter add/remove code is below:
display.getAddChartButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
if (widget == null) {
Runnable onLoadCallback = new Runnable() {
public void run() {
PieChart content = new PieChart(createTable(), createOptions());
// Label content = new Label("Content");
display.getPanel().add(content);
widget = content;
}
};
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}
}
});
display.getRemoveChartButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
if (widget != null) {
display.getPanel().remove(widget);
widget = null;
}
}
});
private AbstractDataTable createTable() {
DataTable data = DataTable.create();
data.addColumn(ColumnType.STRING, "Task");
data.addColumn(ColumnType.NUMBER, "Hours per Day");
data.addRows(2);
data.setValue(0, 0, "Work");
data.setValue(0, 1, 14);
data.setValue(1, 0, "Sleep");
data.setValue(1, 1, 10);
return data;
}
private Options createOptions() {
Options options = Options.create();
options.setWidth(400);
options.setHeight(240);
options.setTitle("My Daily Activities");
return options;
}
I've traced the memory leak to the Google Chart API itself. The team is aware of memory leak issues.

How to make GWT Datagrid have its first column fixed and scroll horizontally and vertically

Currently GWT DataGrid header does this trick with a fixed header row during a vertical scroll. Is there a way to acheive the same on an entire (first) column?
I have implemented ScrolledGrid that freezes first column in DataGrid. You need to use it instead of DataGrid in order to make first column be frozen.
import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
*
* #author Yuri Plaksyuk
*/
public class ScrolledGrid extends DataGrid {
private final Text cssText;
private boolean addedClass = false;
private int currentScrollLeft = 0;
public ScrolledGrid() {
cssText = Document.get().createTextNode("");
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(cssText);
HeaderPanel headerPanel = (HeaderPanel) getWidget();
headerPanel.getElement().insertFirst(styleElement);
final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
scrollPanel.addScrollHandler(new ScrollHandler() {
#Override
public void onScroll(ScrollEvent event) {
int scrollLeft = scrollPanel.getHorizontalScrollPosition();
if (scrollLeft != currentScrollLeft) {
StringBuilder css = new StringBuilder();
if (scrollLeft > 0) {
css.append(".ScrolledGrid-frozen {");
css.append("background-color: inherit;");
css.append("}");
css.append(".ScrolledGrid-frozen div {");
css.append("position: absolute;");
css.append("left: ").append(scrollLeft).append("px;");
css.append("width: ").append(getColumnWidth(getColumn(0))).append(";");
css.append("padding-left: 1.3em;");
css.append("padding-right: 0.5em;");
css.append("margin-top: -0.7em;");
css.append("white-space: nowrap;");
css.append("background-color: inherit;");
css.append("}");
}
else
css.append(".ScrolledGrid-frozen { }");
css.append("th.ScrolledGrid-frozen { background-color: white; }");
cssText.setData(css.toString());
if (!addedClass) {
NodeList<TableRowElement> rows;
TableRowElement row;
TableCellElement cell;
rows = getTableHeadElement().getRows();
for (int i = 0; i < rows.getLength(); ++i) {
row = rows.getItem(i);
cell = row.getCells().getItem(0);
cell.setInnerHTML("<div>" + cell.getInnerHTML() + "</div>");
cell.addClassName("ScrolledGrid-frozen");
}
rows = getTableBodyElement().getRows();
for (int i = 0; i < rows.getLength(); ++i) {
row = rows.getItem(i);
cell = row.getCells().getItem(0);
cell.addClassName("ScrolledGrid-frozen");
}
addedClass = true;
}
currentScrollLeft = scrollLeft;
}
}
});
}
}
Unfortunately, some CSS values are hard-coded.
I adapted Yuri's solution to achieve the following goals:
does not flicker
copes with arbitrary row-heights
works with SelectionModel
more uniform solution
It does not mess with the columns itself, but instead shows arbitrary "frozen" information on row-level.
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.cellview.client.DefaultCellTableBuilder;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
/**
* #author Daniel Lintner
*
* A DataGrid extension with the ability to display some row-level-information
* when scrolling left (horizontal), hence important columns out of sight of the user.
*/
public class FrozenDataGrid extends DataGrid
{
//textnode getting updated dynamically when scolling horizontally
private Text cssText;
//the latest scroll-position
private int currentScrollLeft = 0;
//an object extracting String-info from your rowdata
private FrozenValueProvider valueProvider;
//inject basic styling into the document - once
//this is how the frozen row-info looks like
static
{
Text baseCss = Document.get().createTextNode("");
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(baseCss);
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-base {");
css.append("position: absolute;");
css.append("background-color: gray;");
css.append("padding: .3em;");
css.append("padding-left: .5em;");
css.append("padding-right: .5em;");
css.append("border-radius: 3px 3px;");
css.append("transition: opacity 500ms;");
css.append("color: white;");
css.append("margin-top: 2px;");
css.append("white-space: nowrap;");
css.append("}");
baseCss.setData(css.toString());
Document.get().getBody().insertFirst(styleElement);
}
public FrozenDataGrid()
{
super();
init();
}
public FrozenDataGrid(int pageSize, DataGrid.Resources resources)
{
super(pageSize, resources);
init();
}
public void init()
{
//create a css textnode
cssText = Document.get().createTextNode("");
//create dynamic css Style
StyleElement styleElement = Document.get().createStyleElement();
styleElement.setType("text/css");
styleElement.appendChild(cssText);
//append the initial style condition
//todo the name of this style might be built dynamically per instance - if multiple grid-instances exist/not the use-case by now
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
cssText.setData(css.toString());
//set a custom CellTableBuilder in order to inject the info-div to the row
setTableBuilder(new DefaultCellTableBuilder(this)
{
#Override
public void buildRowImpl(final Object rowValue, final int absRowIndex)
{
//do what DefaultCellTableBuilder does
super.buildRowImpl(rowValue, absRowIndex);
//only do something if there is a valueProvider
if(valueProvider != null) {
//we do this deferred because this row has to created first in order to access it
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand()
{
#Override
public void execute()
{
createInfoDiv(getTableBodyElement().getRows().getItem(absRowIndex % getPageSize()), rowValue);
}
});
}
}
});
//fetch the ScrollPanel from the grid
HeaderPanel headerPanel = (HeaderPanel) getWidget();
headerPanel.getElement().insertFirst(styleElement);
final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
//setup a timer handling the left-offset-css thing
//we use a timer to be able to cancel this operation -> e.g. continuous scroll
final Timer timer = new Timer(){
#Override
public void run() {
StringBuilder css = new StringBuilder();
//we need to left-offset the info-divs
if (scrollPanel.getHorizontalScrollPosition() > 100)
{
css.append(".ScrolledGrid-frozen {");
css.append("left: ").append(3 + scrollPanel.getHorizontalScrollPosition()).append("px;");
css.append("opacity: 1;");
css.append("}");
}
//we are close to the leftmost scroll position: info hidden
else
{
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
}
cssText.setData(css.toString());
}
};
//track scrolling
scrollPanel.addScrollHandler(new ScrollHandler()
{
#Override
public void onScroll(ScrollEvent event)
{
//cancel previous actions to scroll events
if(timer.isRunning())
timer.cancel();
//actual horizontal scrollposition
int scrollLeft = scrollPanel.getHorizontalScrollPosition();
//a horizontal scroll takes places
if (scrollLeft != currentScrollLeft)
{
//first we hide the row-info
StringBuilder css = new StringBuilder();
css.append(".ScrolledGrid-frozen {");
css.append("opacity:0;");
css.append("}");
cssText.setData(css.toString());
//render left offset after a delay
timer.schedule(500);
//remember the current horizontal position
currentScrollLeft = scrollLeft;
}
}
});
}
private void createInfoDiv(TableRowElement row, Object value)
{
//create a div element and add value and style to it
DivElement div = Document.get().createDivElement();
div.setInnerText(valueProvider.getFrozenValue(value));
div.addClassName("ScrolledGrid-base");
div.addClassName("ScrolledGrid-frozen");
//we add it to the first child of the row, because added as child of the row directly
// confuses the CellTable with coordinating header positions
row.getFirstChildElement().insertFirst(div);
}
public void setFrozenValueProvider(FrozenValueProvider valueProvider) {
this.valueProvider = valueProvider;
}
public interface FrozenValueProvider<T>{
String getFrozenValue(T data);
}
}
Hope this helps developers on this rarely and unsatisfactorily solved problem.
And... there is still room for improvement left.
Cheers Dan

How to clean an AnnotatedTimeline gwt visualization chart

I am dealing with a problem with annotatedtimelines.
I have to draw some charts depending on the tab that the user is, so when the tab is changed I clean the current chart and draw the new data. But how to do that?
For now I am removing all the rows, but it is not working.
Can someone help me?
here is the code:
...
//Creating Columns
dataTable.addColumn(ColumnType.DATETIME, "Time");
dataTable.addColumn(ColumnType.NUMBER, "Realtime Consumption");
dataTable.addColumn(ColumnType.NUMBER, "Historical Consumption");
//Create options
options.setDisplayAnnotations(false);
options.setDisplayZoomButtons(false);
options.setScaleType(AnnotatedTimeLine.ScaleType.FIXED);
options.setLegendPosition(AnnotatedTimeLine.AnnotatedLegendPosition.SAME_ROW);
options.setAllowRedraw(true);
options.setDisplayRangeSelector(false);
options.setFill(30);
//to parse the time
DateTimeFormat dtf = DateTimeFormat.getFormat("hh:mm:ss");
//For each item of the list
for(int i = 0; i < list.size(); i++){
//get date
Date date = new Date(list.getTimeAt(i));
//get hh:mm:ss
String time = date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
//add row
dataTable.addRow();
dataTable.setValue(dataTable.getNumberOfRows() - 1, 0, dtf.parse(time));
dataTable.setValue(dataTable.getNumberOfRows() - 1, 2, list.getDataAt(i));
}
/**
* To clean the chart
*/
public void cleanChart(){
//Remove all rows
this.dataTable.removeRows(0, dataTable.getNumberOfRows());
//Redraw the chart
this.draw(this.dataTable, this.options);
}
Thanks,
MaurĂ­cio
It is very strange, but I did it (that seems ok, because I'd create another datatable), and it still not working. The old data continues there.
I have a class that extends AnnotatedTimeLine, and the clean method is now:
/**
* Method to clean the annotated time line
*/
public void clean() {
//Create new table
this.dataTable = DataTable.create();
//Create columns
this.dataTable.addColumn(ColumnType.DATETIME, "Time");
this.dataTable.addColumn(ColumnType.NUMBER, "Data 1");
this.dataTable.addColumn(ColumnType.NUMBER, "Data 2");
//Redraw the chart with the same options
this.draw(this.dataTable, this.options);
}
Any idea?
Thanks!
You need to recreate DataTable for your new data and don't need to do
this.dataTable.removeRows(0, dataTable.getNumberOfRows());
I have something like this
public void reloadChart(List<SharedBean> list, String titleX) {
viz.draw(getChartData(), getOptions(titleX));
}
private DataTable getChartData() {
DataTable data = DataTable.create();
data.addColumn(ColumnType.STRING, "column");
data.addColumn(ColumnType.NUMBER, "value");
data.addRows(list.size());
int row = 0;
int i = 0;
for(SharedBean bean: list){
......
}
return data;
}