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. 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);
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");
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.
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
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;
}