/* * Copyright 2012 AndroidPlot.com * * 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 com.androidplot.demos; import android.app.Activity; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Paint; import android.os.Bundle; import android.widget.CheckBox; import android.widget.CompoundButton; import com.androidplot.util.PixelUtils; import com.androidplot.xy.XYSeries; import com.androidplot.ui.*; import com.androidplot.xy.*; import java.text.DecimalFormat; import java.text.FieldPosition; import java.text.NumberFormat; import java.text.ParsePosition; import java.util.Arrays; /** * Demonstration of the usage of Marker and RectRegion. */ public class XYRegionExampleActivity extends Activity { private static final float HOME_RUN_DIST = 325; private static final int LINE_THICKNESS_DP = 2; private static final int POINT_SIZE_DP = 6; private XYPlot plot; private final Number[] timHits = {105, 252, 220, 350, 12, 250, 353}; private final Number[] nickHits = {110, 191, 61, 371, 289, 101, 10}; private final Number[] joeHits = {25, 375, 364, 128, 178, 289, 346}; private final Number[] jamesHits = {250, 285, 295, 211, 311, 365, 241}; private LineAndPointFormatter timFormatter; private LineAndPointFormatter nickFormatter; private LineAndPointFormatter joeFormatter; private LineAndPointFormatter jamesFormatter; private XYSeries timSeries; private XYSeries nickSeries; private XYSeries joeSeries; private XYSeries jamesSeries; private RectRegion shortRegion; private RectRegion warmupRegion; private RectRegion homeRunRegion; //private XYRegionFormatter rf1; private XYRegionFormatter shortRegionFormatter; private XYRegionFormatter warmupRegionFormatter; private XYRegionFormatter homeRunRegionFormatter; //private XYRegionFormatter rf5; private CheckBox timCB; private CheckBox nickCB; private CheckBox joeCB; private CheckBox jamesCB; private CheckBox r2CheckBox; private CheckBox r3CheckBox; private CheckBox r4CheckBox; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.xyregion_example); plot = (XYPlot) findViewById(R.id.xyRegionExamplePlot); timCB = (CheckBox) findViewById(R.id.s1CheckBox); timCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onS1CheckBoxClicked(); } }); nickCB = (CheckBox) findViewById(R.id.s2CheckBox); nickCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onS2CheckBoxClicked(); } }); joeCB = (CheckBox) findViewById(R.id.s3CheckBox); joeCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onS3CheckBoxClicked(); } }); jamesCB = (CheckBox) findViewById(R.id.s4CheckBox); jamesCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onS4CheckBoxClicked(); } }); r2CheckBox = (CheckBox) findViewById(R.id.r2CheckBox); r2CheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onCheckBoxClicked(r2CheckBox, timFormatter, shortRegionFormatter, shortRegion); } }); r3CheckBox = (CheckBox) findViewById(R.id.r3CheckBox); r3CheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onCheckBoxClicked(r3CheckBox, nickFormatter, warmupRegionFormatter, warmupRegion); } }); r4CheckBox = (CheckBox) findViewById(R.id.r4CheckBox); r4CheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { onCheckBoxClicked(r4CheckBox, nickFormatter, homeRunRegionFormatter, homeRunRegion); } }); seriesSetup(); markerSetup(); axisLabelSetup(); regionSetup(); makePlotPretty(); } private void onS1CheckBoxClicked() { if(timCB.isChecked()) { plot.addSeries(timSeries, timFormatter); r2CheckBox.setEnabled(true); } else { plot.removeSeries(timSeries); r2CheckBox.setEnabled(false); } plot.redraw(); } private void onS2CheckBoxClicked() { if(nickCB.isChecked()) { plot.addSeries(nickSeries, nickFormatter); r3CheckBox.setEnabled(true); r4CheckBox.setEnabled(true); } else { plot.removeSeries(nickSeries); r3CheckBox.setEnabled(false); r4CheckBox.setEnabled(false); } plot.redraw(); } private void onS3CheckBoxClicked() { if(joeCB.isChecked()) { plot.addSeries(joeSeries, joeFormatter); } else { plot.removeSeries(joeSeries); } plot.redraw(); } private void onS4CheckBoxClicked() { if(jamesCB.isChecked()) { plot.addSeries(jamesSeries, jamesFormatter); } else { plot.removeSeries(jamesSeries); } plot.redraw(); } /** * Processes a check box event * @param cb The checkbox event origin * @param lpf LineAndPointFormatter with which rr and rf are to be added/removed * @param rf The XYRegionFormatter with which rr should be rendered * @param rr The RectRegion to add/remove */ private void onCheckBoxClicked(CheckBox cb, LineAndPointFormatter lpf, XYRegionFormatter rf, RectRegion rr) { if(cb.isChecked()) { lpf.removeRegion(rr); } else { lpf.addRegion(rr, rf); } } /** * Cleans up the plot's general layout and color scheme */ private void makePlotPretty() { // use a 2x5 grid with room for 10 items: plot.getLegendWidget().setTableModel(new DynamicTableModel(4, 2)); // add a semi-transparent black background to the legend // so it's easier to see overlaid on top of our plot: Paint bgPaint = new Paint(); bgPaint.setColor(Color.BLACK); bgPaint.setStyle(Paint.Style.FILL); bgPaint.setAlpha(40); plot.getLegendWidget().setBackgroundPaint(bgPaint); // adjust the padding of the legend widget to look a little nicer: plot.getLegendWidget().setPadding(5, 5, 5, 5); plot.setRangeValueFormat(new NumberFormat() { @Override public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) { return new StringBuffer(value + "'"); } @Override public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) { throw new UnsupportedOperationException("Not yet implemented."); } @Override public Number parse(String string, ParsePosition position) { throw new UnsupportedOperationException("Not yet implemented."); } }); plot.setDomainValueFormat(new DecimalFormat("#")); plot.getLegendWidget().setWidth(PixelUtils.dpToPix(100), SizeLayoutType.FILL); // adjust the legend size so there is enough room // to draw the new legend grid: //plot.getLegendWidget().getHeightMetric().setLayoutType(SizeLayoutType.ABSOLUTE); //plot.getLegendWidget().getWidthMetric().setLayoutType(SizeLayoutType.ABSOLUTE); //plot.getLegendWidget().setSize( // new SizeMetrics(70, SizeLayoutType.ABSOLUTE, 80, SizeLayoutType.ABSOLUTE)); // reposition the grid so that it rests above the bottom-left // edge of the graph widget: plot.getLegendWidget().position( 125, XLayoutStyle.ABSOLUTE_FROM_LEFT, 65, YLayoutStyle.ABSOLUTE_FROM_TOP, AnchorPosition.LEFT_TOP); plot.getGraphWidget().setRangeLabelHorizontalOffset(-1); // add enough space to ensure range value labels arent cut off on the left/right: plot.getGraphWidget().setRangeLabelWidth(25); // add enough space to make sure domain value labels arent cut off on the bottom: plot.getGraphWidget().setDomainLabelWidth(15); plot.getGraphWidget().setDomainLabelVerticalOffset(-6); plot.setRangeBoundaries(0, BoundaryMode.FIXED, 500, BoundaryMode.FIXED); } /** * Create 4 XYSeries from the values defined above add add them to the plot. * Also add some arbitrary regions. */ private void seriesSetup() { // TIM timFormatter = new LineAndPointFormatter( Color.rgb(100, 25, 20), Color.rgb(100, 25, 20), null, null); timFormatter.getLinePaint().setStrokeWidth(PixelUtils.dpToPix(LINE_THICKNESS_DP)); timFormatter.getVertexPaint().setStrokeWidth(PixelUtils.dpToPix(POINT_SIZE_DP)); timSeries = new SimpleXYSeries(Arrays.asList(timHits), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Tim"); plot.addSeries(timSeries, timFormatter); // SERIES #2: nickFormatter = new LineAndPointFormatter( Color.rgb(100, 25, 200), Color.rgb(100, 25, 200), null, null); nickFormatter.getLinePaint().setStrokeWidth(PixelUtils.dpToPix(LINE_THICKNESS_DP)); nickFormatter.getVertexPaint().setStrokeWidth(PixelUtils.dpToPix(POINT_SIZE_DP)); nickSeries = new SimpleXYSeries(Arrays.asList(nickHits), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Nick"); plot.addSeries(nickSeries, nickFormatter); // SERIES #3: joeFormatter = new LineAndPointFormatter( Color.rgb(200, 25, 200), Color.rgb(200, 25, 200), null, null); joeFormatter.getLinePaint().setStrokeWidth(PixelUtils.dpToPix(LINE_THICKNESS_DP)); joeFormatter.getVertexPaint().setStrokeWidth(PixelUtils.dpToPix(POINT_SIZE_DP)); joeSeries = new SimpleXYSeries(Arrays.asList(joeHits), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Joe"); plot.addSeries(joeSeries, joeFormatter); // SERIES #4: jamesFormatter = new LineAndPointFormatter( Color.rgb(220, 25, 20), Color.rgb(220, 25, 20), null, null); jamesFormatter.getLinePaint().setStrokeWidth(PixelUtils.dpToPix(LINE_THICKNESS_DP)); jamesFormatter.getVertexPaint().setStrokeWidth(PixelUtils.dpToPix(POINT_SIZE_DP)); jamesSeries = new SimpleXYSeries(Arrays.asList(jamesHits), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY,"James"); plot.addSeries(jamesSeries, jamesFormatter); plot.setRangeStep(XYStepMode.INCREMENT_BY_VAL, 100); //plot.setTicksPerRangeLabel(1); plot.setDomainStep(XYStepMode.INCREMENT_BY_VAL, 1); } /** * Add some color coded regions to our axis labels. */ private void axisLabelSetup() { // DOMAIN plot.getGraphWidget().addDomainAxisValueLabelRegion( Double.NEGATIVE_INFINITY, 2, new AxisValueLabelFormatter(Color.GRAY)); plot.getGraphWidget().addDomainAxisValueLabelRegion( 2, Double.POSITIVE_INFINITY, new AxisValueLabelFormatter(Color.WHITE)); // RANGE plot.getGraphWidget().addRangeAxisValueLabelRegion( Double.NEGATIVE_INFINITY, HOME_RUN_DIST, new AxisValueLabelFormatter(Color.RED)); plot.getGraphWidget().addRangeAxisValueLabelRegion( HOME_RUN_DIST, Double.POSITIVE_INFINITY, new AxisValueLabelFormatter(Color.GREEN)); } /** * Add some markers to our plot. */ private void markerSetup() { YValueMarker fenwayLfMarker = new YValueMarker( 380, // y-val to mark "Fenway Park LF Wall", // marker label new XPositionMetric( // object instance to set text positioning on the marker PixelUtils.dpToPix(5), // 5dp offset XLayoutStyle.ABSOLUTE_FROM_RIGHT), // offset origin Color.BLUE, // line paint color Color.BLUE); // text paint color YValueMarker attRfMarker = new YValueMarker( 309, // y-val to mark "ATT Park RF Wall", // marker label new XPositionMetric( // object instance to set text positioning on the marker PixelUtils.dpToPix(5), // 5dp offset XLayoutStyle.ABSOLUTE_FROM_RIGHT), // offset origin Color.CYAN, // line paint color Color.CYAN); // text paint color fenwayLfMarker.getTextPaint().setTextSize(PixelUtils.dpToPix(14)); attRfMarker.getTextPaint().setTextSize(PixelUtils.dpToPix(14)); DashPathEffect dpe = new DashPathEffect( new float[]{PixelUtils.dpToPix(2), PixelUtils.dpToPix(2)}, 0); fenwayLfMarker.getLinePaint().setPathEffect(dpe); attRfMarker.getLinePaint().setPathEffect(dpe); plot.addMarker(fenwayLfMarker); plot.addMarker(attRfMarker); } /** * Add some fill regions to our series data */ private void regionSetup() { // and another region: shortRegionFormatter = new XYRegionFormatter(Color.RED); shortRegionFormatter.getPaint().setAlpha(75); shortRegion = new RectRegion(2, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, HOME_RUN_DIST, "Short"); timFormatter.addRegion(shortRegion, shortRegionFormatter); nickFormatter.addRegion(shortRegion, shortRegionFormatter); joeFormatter.addRegion(shortRegion, shortRegionFormatter); jamesFormatter.addRegion(shortRegion, shortRegionFormatter); // the next three regions are horizontal regions with minY/maxY // set to negative and positive infinity respectively. warmupRegionFormatter = new XYRegionFormatter(Color.WHITE); warmupRegionFormatter.getPaint().setAlpha(75); warmupRegion = new RectRegion(0, 2, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, "Warmup"); timFormatter.addRegion(warmupRegion, warmupRegionFormatter); nickFormatter.addRegion(warmupRegion, warmupRegionFormatter); joeFormatter.addRegion(warmupRegion, warmupRegionFormatter); jamesFormatter.addRegion(warmupRegion, warmupRegionFormatter); homeRunRegionFormatter = new XYRegionFormatter(Color.GREEN); homeRunRegionFormatter.getPaint().setAlpha(75); homeRunRegion = new RectRegion(2, Double.POSITIVE_INFINITY, HOME_RUN_DIST, Double.POSITIVE_INFINITY, "H. Run"); timFormatter.addRegion(homeRunRegion, homeRunRegionFormatter); nickFormatter.addRegion(homeRunRegion, homeRunRegionFormatter); joeFormatter.addRegion(homeRunRegion, homeRunRegionFormatter); jamesFormatter.addRegion(homeRunRegion, homeRunRegionFormatter); nickFormatter.setFillDirection(FillDirection.RANGE_ORIGIN); } }