/* * Copyright 2015 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.pam.codenamehippie.ui; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.os.Bundle; import android.util.Log; import android.util.Pair; import android.view.MotionEvent; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.SeekBar; import android.widget.Spinner; import com.androidplot.LineRegion; import com.androidplot.ui.AnchorPosition; import com.androidplot.ui.SeriesAndFormatter; import com.androidplot.ui.SeriesRenderer; import com.androidplot.ui.Size; import com.androidplot.ui.SizeLayoutType; import com.androidplot.ui.TextOrientationType; import com.androidplot.ui.XLayoutStyle; import com.androidplot.ui.YLayoutStyle; import com.androidplot.ui.widget.TextLabelWidget; import com.androidplot.util.PixelUtils; import com.androidplot.xy.BarFormatter; import com.androidplot.xy.BarRenderer; import com.androidplot.xy.BoundaryMode; import com.androidplot.xy.SimpleXYSeries; import com.androidplot.xy.XYPlot; import com.androidplot.xy.XYSeries; import com.androidplot.xy.XYSeriesFormatter; import com.pam.codenamehippie.HippieApplication; import com.pam.codenamehippie.R; import com.pam.codenamehippie.modele.TransactionModele; import com.pam.codenamehippie.modele.depot.DepotManager; import com.pam.codenamehippie.modele.depot.ObservateurDeDepot; import com.pam.codenamehippie.modele.depot.TransactionModeleDepot; import java.io.IOException; import java.text.DateFormatSymbols; import java.text.FieldPosition; import java.text.NumberFormat; import java.text.ParsePosition; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; /** * L'exemple le plus simple possible d'utiliser AndroidPlot pour tracer des données. */ public class Stats_Activity extends HippieActivity implements ObservateurDeDepot<TransactionModele> { private enum SeriesSize { Dix, Vingt, Soixante } class MyBarFormatter extends BarFormatter { public MyBarFormatter(int fillColor, int borderColor) { super(fillColor, borderColor); } @Override public Class<? extends SeriesRenderer> getRendererClass() { return MyBarRenderer.class; } @Override public SeriesRenderer getRendererInstance(XYPlot plot) { return new MyBarRenderer(plot); } } class MyBarRenderer extends BarRenderer<MyBarFormatter> { public MyBarRenderer(XYPlot plot) { super(plot); } /** * L'application de cette méthode pour nous permettre d'injecter votre * getFormatter de sélection spéciale. * * * @param index index du point d'être rendue. * @param series XYSeries à laquelle le point d'être rendus appartient. * @return */ @Override public MyBarFormatter getFormatter(int index, XYSeries series) { if (Stats_Activity.this.selection != null && Stats_Activity.this.selection.second == series && Stats_Activity.this.selection.first == index) { return Stats_Activity.this.selectionFormatter; } else { return this.getFormatter(series); } } } // Créer quelques tableaux de valeurs y pour tracer: Number[] series1Numbers10 = {2, null, 5, 2, 7, 4, 3, 7, 4, 5}; Number[] series1Numbers = this.series1Numbers10; // private static final String NO_SELECTION_TXT = "Touch bar to select."; private XYPlot plot; private CheckBox series1CheckBox; private Spinner spRenderStyle, spWidthStyle, spSeriesSize; private SeekBar sbFixedWidth, sbVariableWidth; private XYSeries series1; private MyBarFormatter formatter1; private MyBarFormatter selectionFormatter; private TextLabelWidget selectionWidget; private Pair<Integer, XYSeries> selection; private Integer orgId; @Override protected void onPause() { super.onPause(); } @Override protected void onResume() { super.onResume(); TransactionModeleDepot transactionModeleDepot = DepotManager.getInstance().getTransactionModeleDepot(); // transactionModeleDepot.ajouterUnObservateur(this); if (this.orgId != null && this.orgId != -1) { // TODO: Ajouter 2 DatePicker dans le layout list_statistique Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, 2016); Date dateDebut = calendar.getTime(); calendar = Calendar.getInstance(); Date dateFin = calendar.getTime(); transactionModeleDepot.peuplerTransactions(this.orgId, dateDebut, dateFin); } } @Override public void surDebutDeRequete() { this.afficherLaProgressBar(); } @Override public void surChangementDeDonnees(List<TransactionModele> modeles) { } @Override public void surFinDeRequete() { this.cacherLaProgressbar(); } @Override public void surErreur(IOException e) { //todo: snackbar Log.e(this.getClass().getSimpleName(), e.getMessage(), e); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.activity_stats); // initialize our XYPlot reference: this.plot = (XYPlot) this.findViewById(R.id.plot); this.formatter1 = new MyBarFormatter(Color.argb(200, 78, 130, 189), Color.LTGRAY);//Bleu this.selectionFormatter = new MyBarFormatter(Color.argb(1000, 224, 222, 84), Color.WHITE); this.selectionWidget = new TextLabelWidget(this.plot.getLayoutManager(), this.getString(R.string.stats_non_selectionne), new Size(PixelUtils.dpToPix(100), SizeLayoutType.ABSOLUTE, PixelUtils.dpToPix(100), SizeLayoutType.ABSOLUTE), TextOrientationType.HORIZONTAL); this.selectionWidget.setPaddingLeft(10); this.selectionWidget.getLabelPaint().setTextSize(PixelUtils.dpToPix(20)); // ajouter un fond semi-transparent sombre pour le widget étiquette de sélection: Paint p = new Paint(); p.setARGB(100, 0, 0, 0); this.selectionWidget.setBackgroundPaint(p); this.selectionWidget.position(0, XLayoutStyle.RELATIVE_TO_CENTER, PixelUtils.dpToPix(60), YLayoutStyle.ABSOLUTE_FROM_TOP, AnchorPosition.TOP_MIDDLE); this.selectionWidget.pack(); // réduire le nombre d'étiquettes de la gamme this.plot.setTicksPerRangeLabel(3); this.plot.setRangeLowerBoundary(0, BoundaryMode.FIXED); this.plot.getGraphWidget().getGridBox().setPadding(30, 10, 30, 0); this.plot.setTicksPerDomainLabel(2); // Lister la configuration de cases à cocher: this.series1CheckBox = (CheckBox) this.findViewById(R.id.tv_statistiques_valeur_total); this.series1CheckBox.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean b) { Stats_Activity.this.onS1CheckBoxClicked(b); } }); this.plot.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { Stats_Activity.this.onPlotClicked( new PointF(motionEvent.getX(), motionEvent.getY())); } return true; } }); this.spRenderStyle = (Spinner) this.findViewById(R.id.spRenderStyle); BarRenderer.BarRenderStyle arr[] = {BarRenderer.BarRenderStyle.SIDE_BY_SIDE, BarRenderer.BarRenderStyle.STACKED}; ArrayAdapter<BarRenderer.BarRenderStyle> adapter = new ArrayAdapter<BarRenderer.BarRenderStyle>(this, android.R.layout.simple_spinner_item, arr); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); this.spRenderStyle.setAdapter(adapter); this.spRenderStyle.setSelection(BarRenderer.BarRenderStyle.STACKED.ordinal()); this.spRenderStyle.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Stats_Activity.this.updatePlot(); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); this.spWidthStyle = (Spinner) this.findViewById(R.id.spWidthStyle); ArrayAdapter<BarRenderer.BarWidthStyle> adapter1 = new ArrayAdapter<BarRenderer.BarWidthStyle>(this, android.R.layout.simple_spinner_item, BarRenderer.BarWidthStyle.values()); adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); this.spWidthStyle.setAdapter(adapter1); this.spWidthStyle.setSelection(BarRenderer.BarWidthStyle.VARIABLE_WIDTH.ordinal()); this.spWidthStyle.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { if (BarRenderer.BarWidthStyle.FIXED_WIDTH.equals( Stats_Activity.this.spWidthStyle.getSelectedItem())) { Stats_Activity.this.sbFixedWidth.setVisibility(View.VISIBLE); Stats_Activity.this.sbVariableWidth.setVisibility(View.INVISIBLE); } else { Stats_Activity.this.sbFixedWidth.setVisibility(View.INVISIBLE); Stats_Activity.this.sbVariableWidth.setVisibility(View.VISIBLE); } Stats_Activity.this.updatePlot(); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); this.spSeriesSize = (Spinner) this.findViewById(R.id.spSeriesSize); ArrayAdapter<SeriesSize> adapter11 = new ArrayAdapter<SeriesSize>(this, android.R.layout.simple_spinner_item, SeriesSize.values()); adapter11.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); this.spSeriesSize.setAdapter(adapter11); this.spSeriesSize.setSelection(SeriesSize.Dix.ordinal()); this.spSeriesSize.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { switch ((SeriesSize) arg0.getSelectedItem()) { case Dix: Stats_Activity.this.series1Numbers = Stats_Activity.this.series1Numbers10; break; default: break; } Stats_Activity.this.updatePlot(); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); this.sbFixedWidth = (SeekBar) this.findViewById(R.id.sbFixed); this.sbFixedWidth.setProgress(50); this.sbFixedWidth.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { Stats_Activity.this.updatePlot(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); this.sbVariableWidth = (SeekBar) this.findViewById(R.id.sbVariable); this.sbVariableWidth.setProgress(1); this.sbVariableWidth.setVisibility(View.INVISIBLE); this.sbVariableWidth.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { Stats_Activity.this.updatePlot(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); this.plot.setDomainValueFormat(new NumberFormat() { @Override public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) { int year = (int) (value + 0.5d) / 12; int month = (int) ((value + 0.5d) % 12); return new StringBuffer(DateFormatSymbols.getInstance().getShortMonths()[month] + " '0" + year); } @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."); } }); this.updatePlot(); } private void updatePlot() { // Retirer toutes les séries en cours de chaque parcelle this.plot.clear(); // Configuration de votre série avec le nombre sélectionné d'éléments this.series1 = new SimpleXYSeries(Arrays.asList(this.series1Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Totale"); // ajouter une nouvelle série »à la xyplot: if (this.series1CheckBox.isChecked()) { this.plot.addSeries(this.series1, this.formatter1); } // Configuration du BarRenderer avec vos options sélectionnées MyBarRenderer renderer = ((MyBarRenderer) this.plot.getRenderer(MyBarRenderer.class)); renderer.setBarRenderStyle( (BarRenderer.BarRenderStyle) this.spRenderStyle.getSelectedItem()); renderer.setBarWidthStyle((BarRenderer.BarWidthStyle) this.spWidthStyle.getSelectedItem()); renderer.setBarWidth(this.sbFixedWidth.getProgress()); renderer.setBarGap(this.sbVariableWidth.getProgress()); if (BarRenderer.BarRenderStyle.STACKED.equals(this.spRenderStyle.getSelectedItem())) { this.plot.setRangeTopMin(60); } else { this.plot.setRangeTopMin(0); } this.plot.redraw(); } private void onPlotClicked(PointF point) { // Assurez-vous que le point se trouve dans la zone graphique. nous utilisons la grille rect // car il tient compte des marges et le padding ainsi. if (this.plot.getGraphWidget() .getGridDimensions() .marginatedRect.contains(point.x, point.y)) { Number x = this.plot.getXVal(point); Number y = this.plot.getYVal(point); this.selection = null; double xDistance = 0; double yDistance = 0; // trouver la valeur la plus proche de la sélection: for (SeriesAndFormatter<XYSeries, ? extends XYSeriesFormatter> sfPair : this.plot .getSeriesRegistry()) { XYSeries series = sfPair.getSeries(); for (int i = 0; i < series.size(); i++) { Number thisX = series.getX(i); Number thisY = series.getY(i); if (thisX != null && thisY != null) { double thisXDistance = LineRegion.measure(x, thisX).doubleValue(); double thisYDistance = LineRegion.measure(y, thisY).doubleValue(); if (this.selection == null) { this.selection = new Pair<Integer, XYSeries>(i, series); xDistance = thisXDistance; yDistance = thisYDistance; } else if (thisXDistance < xDistance) { this.selection = new Pair<Integer, XYSeries>(i, series); xDistance = thisXDistance; yDistance = thisYDistance; } else if (thisXDistance == xDistance && thisYDistance < yDistance && thisY.doubleValue() >= y.doubleValue()) { this.selection = new Pair<Integer, XYSeries>(i, series); xDistance = thisXDistance; yDistance = thisYDistance; } } } } } else { // trouver la valeur la plus proche de la sélection: this.selection = null; } if (this.selection == null) { this.selectionWidget.setText(this.getString(R.string.stats_non_selectionne)); this.selectionWidget.setPaddingRight(35); } else { this.selectionWidget.setText(this.selection.second.getTitle() + " : " + this.selection.second.getY(this.selection.first) + " $ "); } this.plot.redraw(); } private void onS1CheckBoxClicked(boolean checked) { if (checked) { this.plot.addSeries(this.series1, this.formatter1); } else { this.plot.removeSeries(this.series1); } this.plot.redraw(); } }