package com.griddynamics.jagger.webclient.client.components; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.DomEvent; import com.google.gwt.user.client.ui.*; import com.googlecode.gflot.client.Pan; import com.googlecode.gflot.client.SimplePlot; import com.griddynamics.jagger.dbapi.dto.PlotIntegratedDto; import com.griddynamics.jagger.dbapi.model.MetricNode; import com.griddynamics.jagger.webclient.client.resources.JaggerResources; /** * class that represents plot with all its functionality */ public class PlotRepresentation extends LayoutPanel { private FlowPanel zoomPanel; private SimplePlot simplePlot; private Label xLabel; private MetricNode metricNode; private MyScroll scrollbar; // model of plot private PlotIntegratedDto plotIntegratedDto; private LegendTree legendTree; private LegendState legendState = LegendState.DEFAULT; private final int TOTAL_BORDERS_WIDTH = 4; private final int DEFAULT_LEGEND_PANEL_WIDTH = 200; private final int LEGEND_PANEL_WIDTH; private final int ZOOM_PANEL_HEIGHT = 20; private final int SCROLL_PANEL_HEIGHT = 20; private final int X_AXIS_LABEL_HEIGHT = 20; private Label legendLabel; public int getXAxisLabelHeight() { return X_AXIS_LABEL_HEIGHT; } public int getScrollPanelHeight() { return SCROLL_PANEL_HEIGHT; } public int getZoomPanelHeight() { return ZOOM_PANEL_HEIGHT; } /** * Range to scroll to */ private double maxRange = 1; public PlotRepresentation( MetricNode metricNode, FlowPanel zoomPanel, SimplePlot simplePlot, LegendTree legendTree, String xLabelString, PlotIntegratedDto plotIntegratedDto) { super(); this.setWidth("100%"); this.zoomPanel = zoomPanel; this.zoomPanel.setHeight(ZOOM_PANEL_HEIGHT + "px"); this.plotIntegratedDto = plotIntegratedDto; legendLabel = new Label(legendState.getMessage()); legendLabel.setStyleName(JaggerResources.INSTANCE.css().zoomLabel()); legendLabel.addClickHandler(new LegendLabelClickHandler()); // fixed size of show/hide legend label legendLabel.setWidth("100px"); zoomPanel.add(legendLabel); this.simplePlot = simplePlot; this.metricNode = metricNode; this.xLabel = new Label(xLabelString); this.xLabel.addStyleName(JaggerResources.INSTANCE.css().xAxisLabel()); this.xLabel.setHeight(X_AXIS_LABEL_HEIGHT + "px"); this.legendTree = legendTree; // determine legend tree width - trick AbsolutePanel ap = new AbsolutePanel(); ap.setSize("100%", "100%"); ap.add(legendTree); ap.setWidgetPosition(legendTree, 0, 0); RootLayoutPanel.get().add(ap); LEGEND_PANEL_WIDTH = legendTree.getOffsetWidth(); RootLayoutPanel.get().remove(ap); simplePlot.setWidth("100%"); final VerticalPanel vp = new VerticalPanel(); vp.setWidth("100%"); vp.add(zoomPanel); vp.add(simplePlot); HorizontalPanel hp = new HorizontalPanel(); hp.setWidth("100%"); hp.setHeight(SCROLL_PANEL_HEIGHT + "px"); scrollbar = new MyScroll(); scrollbar.setWidth("100%"); scrollbar.setVisible(true); scrollbar.setHorizontalScrollPosition(0); // simple div SimplePanel sp = new SimplePanel(); sp.setVisible(false); hp.add(sp); hp.setCellWidth(sp, simplePlot.getOptions().getYAxisOptions().getLabelWidth().intValue() + "px"); hp.add(scrollbar); vp.add(hp); vp.add(xLabel); this.add(vp); legendTree.setStyleName(JaggerResources.INSTANCE.css().legendPanel()); this.add(legendTree); } public double getMaxRange() { return maxRange; } public void calculateScrollWidth() { if (scrollbar.isAttached()) { double plotWidth = getPlotWidth() - TOTAL_BORDERS_WIDTH; double visibleRange = getVisibleRange(); double ratio = maxRange / visibleRange; scrollbar.setScrollWidth((int) (plotWidth * ratio)); } } public void setMaxRange(double maxRange) { this.maxRange = maxRange; calculateScrollWidth(); } public MyScroll getScrollbar() { return scrollbar; } public FlowPanel getZoomPanel() { return zoomPanel; } public SimplePlot getSimplePlot() { return simplePlot; } public Label getxLabel() { return xLabel; } public PlotIntegratedDto getPlotIntegratedDto() { return plotIntegratedDto; } public LegendTree getLegendTree() { return legendTree; } public MetricNode getMetricNode() { return metricNode; } public void panToPercent(double percent) { double minVisible = simplePlot.getAxes().getX().getMinimumValue(); double visibleRange = getVisibleRange(); double valueOnScaleShouldBe = percent * (maxRange - visibleRange); double deltaInScale = valueOnScaleShouldBe - minVisible; double pixelsToScale = getPlotWidth() / visibleRange; Pan pan = Pan.create().setLeft(deltaInScale * pixelsToScale).setPreventEvent(true); simplePlot.pan(pan); int newHorizontalPosition = (int) ((scrollbar.getMaximumHorizontalScrollPosition() - scrollbar.getMinimumHorizontalScrollPosition()) * percent); if (newHorizontalPosition == scrollbar.getHorizontalScrollPosition()) { // fire scroll event anyway NativeEvent event = Document.get().createScrollEvent(); DomEvent.fireNativeEvent(event, scrollbar); } else { scrollbar.setHorizontalScrollPosition(newHorizontalPosition); } } private double getPlotWidth() { return simplePlot.getOffsetWidth() - simplePlot.getOptions().getYAxisOptions().getLabelWidth(); } private double getVisibleRange() { return simplePlot.getAxes().getX().getMaximumValue() - simplePlot.getAxes().getX().getMinimumValue(); } @Override public void onResize() { calculateScrollWidth(); calculateLegendPosition(); } /** * Put Legend into the right place on PlotRepresentation panel */ private void calculateLegendPosition() { if ( LegendState.HIDE == legendState ) { return; } final int BORDERS = 4; final int DELTA = 3; final int ZOOM_PANEL_WIDTH = zoomPanel.getOffsetHeight(); int legendWidth = (LegendState.DEFAULT == legendState) ? DEFAULT_LEGEND_PANEL_WIDTH : LEGEND_PANEL_WIDTH; legendWidth += 20; // scroll width int legendHeight = calculateLegendHeight(); this.setWidgetRightWidth(legendTree, BORDERS, Style.Unit.PX, legendWidth, Style.Unit.PX); this.setWidgetTopHeight(legendTree, ZOOM_PANEL_WIDTH + BORDERS + DELTA, Style.Unit.PX, legendHeight, Style.Unit.PX); } /** * Calculate height for legend * @return legend's height */ private int calculateLegendHeight() { // height of all plot minus axis labels, borders height. return simplePlot.getOffsetHeight() - X_AXIS_LABEL_HEIGHT - 2 * TOTAL_BORDERS_WIDTH; } /** * Click handler for legend label */ private class LegendLabelClickHandler implements ClickHandler { @Override public void onClick(ClickEvent event) { // get next state legendState = legendState.getNext(); legendLabel.setText(legendState.getMessage()); switch (legendState) { case HIDE: PlotRepresentation.this.setWidgetVisible(legendTree, false); break; default: PlotRepresentation.this.setWidgetVisible(legendTree, true); calculateLegendPosition(); } } } /** * State of the legend with title of legend label */ private enum LegendState { DEFAULT("Full size legend"), FULL_TEXT("Hide legend"), HIDE("Show legend"); private String message; private LegendState(String message) { this.message = message; } public String getMessage() { return message; } LegendState getNext() {return LegendState.values()[(this.ordinal() + 1) % LegendState.values().length];} } }