/**
* Sencha GXT 3.0.0b - Sencha for GWT
* Copyright(c) 2007-2012, Sencha, Inc.
* licensing@sencha.com
*
* http://www.sencha.com/products/gxt/license/
*/
package com.sencha.gxt.explorer.client.chart;
import java.util.ArrayList;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.editor.client.Editor.Path;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.chart.client.chart.Chart;
import com.sencha.gxt.chart.client.chart.RoundNumberProvider;
import com.sencha.gxt.chart.client.chart.series.Primitives;
import com.sencha.gxt.chart.client.chart.series.ScatterSeries;
import com.sencha.gxt.chart.client.chart.series.SeriesLabelConfig;
import com.sencha.gxt.chart.client.chart.series.SeriesRenderer;
import com.sencha.gxt.chart.client.draw.DrawFx;
import com.sencha.gxt.chart.client.draw.HSV;
import com.sencha.gxt.chart.client.draw.RGB;
import com.sencha.gxt.chart.client.draw.sprite.CircleSprite;
import com.sencha.gxt.chart.client.draw.sprite.Sprite;
import com.sencha.gxt.chart.client.draw.sprite.TextSprite;
import com.sencha.gxt.chart.client.draw.sprite.TextSprite.TextAnchor;
import com.sencha.gxt.core.client.ValueProvider;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.ModelKeyProvider;
import com.sencha.gxt.data.shared.PropertyAccess;
import com.sencha.gxt.examples.resources.client.TestData;
import com.sencha.gxt.examples.resources.client.model.Data;
import com.sencha.gxt.explorer.client.model.Example.Detail;
import com.sencha.gxt.fx.client.Draggable;
import com.sencha.gxt.fx.client.animation.Animator;
import com.sencha.gxt.widget.core.client.ContentPanel;
import com.sencha.gxt.widget.core.client.FramedPanel;
import com.sencha.gxt.widget.core.client.Resizable;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.button.ToggleButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData;
import com.sencha.gxt.widget.core.client.event.ActivateEvent;
import com.sencha.gxt.widget.core.client.event.ActivateEvent.ActivateHandler;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent.SelectHandler;
import com.sencha.gxt.widget.core.client.menu.Item;
import com.sencha.gxt.widget.core.client.menu.Menu;
import com.sencha.gxt.widget.core.client.menu.MenuItem;
import com.sencha.gxt.widget.core.client.toolbar.ToolBar;
@Detail(name = "Scatter Renderer Chart", icon = "scatterrendererchart", category = "Charts", classes = {
Data.class, DrawFx.class})
public class ScatterRendererExample implements IsWidget, EntryPoint {
public interface DataPropertyAccess extends PropertyAccess<Data> {
ValueProvider<Data, Double> data1();
ValueProvider<Data, Double> data2();
ValueProvider<Data, Double> data3();
ValueProvider<Data, String> name();
@Path("name")
ModelKeyProvider<Data> nameKey();
}
private static final DataPropertyAccess dataAccess = GWT.create(DataPropertyAccess.class);
private ScatterSeries<Data> series = new ScatterSeries<Data>();
private ValueProvider<Data, Double> radiusField;
private ValueProvider<Data, Double> colorField;
private ValueProvider<Data, Double> grayField;
private double maxRadius = 50;
private RGB minColor = new RGB(250, 20, 20);
private RGB maxColor = new RGB(127, 0, 220);
private RGB minGray = new RGB(20, 20, 20);
private RGB maxGray = new RGB(220, 220, 220);
private ArrayList<RGB> colors = new ArrayList<RGB>();
private ArrayList<RGB> grays = new ArrayList<RGB>();
private Chart<Data> chart;
public Widget asWidget() {
// set up colors
colors.add(new RGB(250, 20, 20));
colors.add(new RGB(20, 250, 20));
colors.add(new RGB(20, 20, 250));
colors.add(new RGB(127, 0, 240));
colors.add(new RGB(213, 70, 121));
colors.add(new RGB(44, 153, 201));
colors.add(new RGB(146, 6, 157));
colors.add(new RGB(49, 149, 0));
colors.add(new RGB(249, 153, 0));
grays.add(new RGB(20, 20, 20));
grays.add(new RGB(80, 80, 80));
grays.add(new RGB(120, 120, 120));
grays.add(new RGB(180, 180, 180));
grays.add(new RGB(220, 220, 220));
grays.add(new RGB(250, 250, 250));
final ListStore<Data> store = new ListStore<Data>(dataAccess.nameKey());
store.addAll(TestData.getData(12, 0, 100));
chart = new Chart<Data>();
chart.setStore(store);
chart.setDefaultInsets(50);
chart.setShadowChart(true);
series.setXField(dataAccess.data1());
series.setYField(dataAccess.data2());
Sprite marker = Primitives.circle(0, 0, 20);
marker.setFill(RGB.BLUE);
series.setMarkerConfig(marker);
TextSprite textConfig = new TextSprite();
textConfig.setFill(new RGB("#333"));
textConfig.setTextAnchor(TextAnchor.MIDDLE);
SeriesLabelConfig<Data> labelConfig = new SeriesLabelConfig<Data>();
labelConfig.setSpriteConfig(textConfig);
labelConfig.setLabelContrast(true);
labelConfig.setValueProvider(dataAccess.data3(), new RoundNumberProvider<Double>());
series.setLabelConfig(labelConfig);
chart.addSeries(series);
TextButton regenerate = new TextButton("Reload Data");
regenerate.addSelectHandler(new SelectHandler() {
@Override
public void onSelect(SelectEvent event) {
store.clear();
store.addAll(TestData.getData(12, 0, 100));
chart.redrawChart();
}
});
ToggleButton animation = new ToggleButton("Animate");
animation.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
chart.setAnimated(event.getValue());
}
});
animation.setValue(true, true);
ToggleButton shadow = new ToggleButton("Shadow");
shadow.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
chart.setShadowChart(event.getValue());
chart.redrawChart();
}
});
shadow.setValue(true);
TextButton xAxis = new TextButton("Select X Axis");
Menu xAxisMenu = new Menu();
MenuItem xAxisData1 = new MenuItem("data1");
xAxisData1.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
series.setXField(dataAccess.data1());
series.drawSeries();
}
});
xAxisMenu.add(xAxisData1);
MenuItem xAxisData2 = new MenuItem("data2");
xAxisData2.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
series.setXField(dataAccess.data2());
series.drawSeries();
}
});
xAxisMenu.add(xAxisData2);
MenuItem xAxisData3 = new MenuItem("data3");
xAxisData3.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
series.setXField(dataAccess.data3());
series.drawSeries();
}
});
xAxisMenu.add(xAxisData3);
xAxis.setMenu(xAxisMenu);
TextButton yAxis = new TextButton("Select Y Axis");
Menu yAxisMenu = new Menu();
MenuItem yAxisData1 = new MenuItem("data1");
yAxisData1.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
series.setYField(dataAccess.data1());
series.drawSeries();
}
});
yAxisMenu.add(yAxisData1);
MenuItem yAxisData2 = new MenuItem("data2");
yAxisData2.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
series.setYField(dataAccess.data2());
series.drawSeries();
}
});
yAxisMenu.add(yAxisData2);
MenuItem yAxisData3 = new MenuItem("data3");
yAxisData3.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
series.setYField(dataAccess.data3());
series.drawSeries();
}
});
yAxisMenu.add(yAxisData3);
yAxis.setMenu(yAxisMenu);
TextButton color = new TextButton("Select Color");
Menu colorMenu = new Menu();
MenuItem colorData1 = new MenuItem("data1");
colorData1.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
colorField = dataAccess.data1();
grayField = null;
refresh();
}
});
colorMenu.add(colorData1);
MenuItem colorData2 = new MenuItem("data2");
colorData2.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
colorField = dataAccess.data2();
grayField = null;
refresh();
}
});
colorMenu.add(colorData2);
MenuItem colorData3 = new MenuItem("data3");
colorData3.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
colorField = dataAccess.data3();
grayField = null;
refresh();
}
});
colorMenu.add(colorData3);
MenuItem colorFrom = new MenuItem("Color From");
Menu colorFromMenu = new Menu();
for (int i = 0; i < colors.size(); i++) {
final int index = i;
MenuItem colorFromItem = new MenuItem(colors.get(index).toString());
colorFromItem.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
minColor = colors.get(index);
refresh();
}
});
colorFromMenu.add(colorFromItem);
}
colorFrom.setSubMenu(colorFromMenu);
colorMenu.add(colorFrom);
MenuItem colorTo = new MenuItem("Color To");
Menu colorToMenu = new Menu();
for (int i = 0; i < colors.size(); i++) {
final int index = i;
MenuItem colorToItem = new MenuItem(colors.get(index).toString());
colorToItem.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxColor = colors.get(index);
refresh();
}
});
colorToMenu.add(colorToItem);
}
colorTo.setSubMenu(colorToMenu);
colorMenu.add(colorTo);
color.setMenu(colorMenu);
TextButton grayscale = new TextButton("Select GrayScale");
Menu grayMenu = new Menu();
MenuItem grayData1 = new MenuItem("data1");
grayData1.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
grayField = dataAccess.data1();
colorField = null;
refresh();
}
});
grayMenu.add(grayData1);
MenuItem grayData2 = new MenuItem("data2");
grayData2.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
grayField = dataAccess.data2();
colorField = null;
refresh();
}
});
grayMenu.add(grayData2);
MenuItem grayData3 = new MenuItem("data3");
grayData3.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
grayField = dataAccess.data3();
colorField = null;
refresh();
}
});
grayMenu.add(grayData3);
MenuItem grayFrom = new MenuItem("Gray From");
Menu grayFromMenu = new Menu();
for (int i = 0; i < grays.size(); i++) {
final int index = i;
MenuItem grayFromItem = new MenuItem(grays.get(index).toString());
grayFromItem.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
minGray = grays.get(index);
refresh();
}
});
grayFromMenu.add(grayFromItem);
}
grayFrom.setSubMenu(grayFromMenu);
grayMenu.add(grayFrom);
MenuItem grayTo = new MenuItem("Gray To");
Menu grayToMenu = new Menu();
for (int i = 0; i < grays.size(); i++) {
final int index = i;
MenuItem grayToItem = new MenuItem(grays.get(index).toString());
grayToItem.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxGray = grays.get(index);
refresh();
}
});
grayToMenu.add(grayToItem);
}
grayTo.setSubMenu(grayToMenu);
grayMenu.add(grayTo);
grayscale.setMenu(grayMenu);
TextButton radius = new TextButton("Select Radius");
Menu radiusMenu = new Menu();
MenuItem radiusData1 = new MenuItem("data1");
radiusData1.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
radiusField = dataAccess.data1();
refresh();
}
});
radiusMenu.add(radiusData1);
MenuItem radiusData2 = new MenuItem("data2");
radiusData2.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
radiusField = dataAccess.data2();
refresh();
}
});
radiusMenu.add(radiusData2);
MenuItem radiusData3 = new MenuItem("data3");
radiusData3.addSelectionHandler(new SelectionHandler<Item>() {
@Override
public void onSelection(SelectionEvent<Item> event) {
radiusField = dataAccess.data3();
refresh();
}
});
radiusMenu.add(radiusData3);
MenuItem maximumRadius = new MenuItem("Max Radius");
Menu maximumRadiusMenu = new Menu();
MenuItem radius20 = new MenuItem("20");
radius20.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxRadius = 20;
refresh();
}
});
maximumRadiusMenu.add(radius20);
MenuItem radius30 = new MenuItem("30");
radius30.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxRadius = 30;
refresh();
}
});
maximumRadiusMenu.add(radius30);
MenuItem radius40 = new MenuItem("40");
radius40.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxRadius = 40;
refresh();
}
});
maximumRadiusMenu.add(radius40);
MenuItem radius50 = new MenuItem("50");
radius50.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxRadius = 50;
refresh();
}
});
maximumRadiusMenu.add(radius50);
MenuItem radius60 = new MenuItem("60");
radius60.addActivateHandler(new ActivateHandler<Item>() {
@Override
public void onActivate(ActivateEvent<Item> event) {
maxRadius = 60;
refresh();
}
});
maximumRadiusMenu.add(radius60);
maximumRadius.setSubMenu(maximumRadiusMenu);
radiusMenu.add(maximumRadius);
radius.setMenu(radiusMenu);
ContentPanel panel = new FramedPanel();
panel.getElement().getStyle().setMargin(10, Unit.PX);
panel.setCollapsible(true);
panel.setHeadingText("Scatter Renderer Chart");
panel.setPixelSize(620, 500);
panel.setBodyBorder(true);
Resizable resize = new Resizable(panel);
resize.setMinHeight(400);
resize.setMinWidth(400);
new Draggable(panel, panel.getHeader()).setUseProxy(false);
ToolBar toolBar = new ToolBar();
toolBar.add(regenerate);
toolBar.add(animation);
toolBar.add(shadow);
toolBar.add(xAxis);
toolBar.add(yAxis);
toolBar.add(color);
toolBar.add(grayscale);
toolBar.add(radius);
VerticalLayoutContainer layout = new VerticalLayoutContainer();
panel.add(layout);
toolBar.setLayoutData(new VerticalLayoutData(1, -1));
layout.add(toolBar);
chart.setLayoutData(new VerticalLayoutData(1, 1));
layout.add(chart);
return panel;
}
public void onModuleLoad() {
RootPanel.get().add(asWidget());
}
private SeriesRenderer<Data> color(final ValueProvider<Data, Double> fieldName, final RGB minColor,
final RGB maxColor, final double minValue, final double maxValue) {
final HSV min = new HSV(minColor);
final HSV max = new HSV(maxColor);
return new SeriesRenderer<Data>() {
@Override
public void spriteRenderer(Sprite sprite, int index, ListStore<Data> store) {
double value = fieldName.getValue(store.get(index));
double delta1 = delta(minValue, maxValue, min.getHue(), max.getHue(), value);
double delta2 = delta(minValue, maxValue, min.getSaturation(), max.getSaturation(), value);
double delta3 = delta(minValue, maxValue, min.getValue(), max.getValue(), value);
if(chart.isAnimated()) {
createFillAnimator(sprite, new RGB(new HSV((int) delta1, (int) delta2, (int) delta3))).run(500);
} else {
sprite.setFill(new RGB(new HSV((int) delta1, (int) delta2, (int) delta3)));
sprite.redraw();
}
}
};
}
private Animator createFillAnimator(final Sprite sprite, RGB color) {
if (!(sprite.getFill() instanceof RGB)) {
return null;
}
RGB origin = (RGB) sprite.getFill();
final int originR = origin.getRed();
final int originG = origin.getGreen();
final int originB = origin.getBlue();
final int deltaR = color.getRed() - originR;
final int deltaG = color.getGreen() - originG;
final int deltaB = color.getBlue() - originB;
return new Animator() {
@Override
protected void onUpdate(double progress) {
sprite.setFill(new RGB(originR + (int) (deltaR * progress), originG + (int) (deltaG * progress), originB
+ (int) (deltaB * progress)));
sprite.redraw();
}
};
}
private Animator createRadiusAnimator(final CircleSprite sprite, double radius) {
final double origin = sprite.getRadius();
final double delta = radius - origin;
return new Animator() {
@Override
protected void onUpdate(double progress) {
sprite.setRadius(origin + (delta * progress));
sprite.redraw();
}
};
}
private double delta(double x, double y, double a, double b, double theta) {
return a + (b - a) * (y - theta) / (y - x);
}
private SeriesRenderer<Data> grayscale(final ValueProvider<Data, Double> fieldName, final RGB minColor,
final RGB maxColor, final double minValue, final double maxValue) {
return new SeriesRenderer<Data>() {
@Override
public void spriteRenderer(Sprite sprite, int index, ListStore<Data> store) {
double value = fieldName.getValue(store.get(index));
double ans = delta(minValue, maxValue, minColor.getGreen(), maxColor.getGreen(), value);
if(chart.isAnimated()) {
createFillAnimator(sprite, new RGB((int) Math.round(ans), (int) Math.round(ans), (int) Math.round(ans))).run(
500);
} else {
sprite.setFill(new RGB((int) Math.round(ans), (int) Math.round(ans), (int) Math.round(ans)));
sprite.redraw();
}
}
};
}
private SeriesRenderer<Data> radius(final ValueProvider<Data, Double> fieldName, final double minRadius,
final double maxRadius, final double minValue, final double maxValue) {
return new SeriesRenderer<Data>() {
@Override
public void spriteRenderer(Sprite sprite, int index, ListStore<Data> store) {
double scale = delta(maxValue, minValue, maxRadius, minRadius, fieldName.getValue(store.get(index)));
scale = maxRadius - scale + minRadius;
if(chart.isAnimated()) {
createRadiusAnimator((CircleSprite) sprite, scale).run(500);
} else {
((CircleSprite) sprite).setRadius(scale);
sprite.redraw();
}
}
};
}
private void refresh() {
series.setRenderer(new SeriesRenderer<Data>() {
@Override
public void spriteRenderer(Sprite sprite, int index, ListStore<Data> store) {
if (colorField != null) {
color(colorField, minColor, maxColor, 0, 100).spriteRenderer(sprite, index, store);
}
if (grayField != null) {
grayscale(grayField, minGray, maxGray, 0, 100).spriteRenderer(sprite, index, store);
}
if (radiusField != null) {
radius(radiusField, 10, maxRadius, 0, 100).spriteRenderer(sprite, index, store);
}
}
});
if(radiusField != null) {
series.setShadowRenderer(radius(radiusField, 10, maxRadius, 0, 100));
}
series.drawSeries();
}
}