Package name.abuchen.portfolio.ui.views.taxonomy

Source Code of name.abuchen.portfolio.ui.views.taxonomy.StackedChartViewer

package name.abuchen.portfolio.ui.views.taxonomy;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import name.abuchen.portfolio.model.Classification;
import name.abuchen.portfolio.model.InvestmentVehicle;
import name.abuchen.portfolio.snapshot.Aggregation;
import name.abuchen.portfolio.snapshot.Aggregation.Period;
import name.abuchen.portfolio.snapshot.AssetPosition;
import name.abuchen.portfolio.snapshot.ClientSnapshot;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.PortfolioPart;
import name.abuchen.portfolio.ui.util.chart.StackedTimelineChart;
import name.abuchen.portfolio.ui.views.taxonomy.TaxonomyModel.NodeVisitor;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.joda.time.DateMidnight;
import org.joda.time.Interval;
import org.swtchart.ISeries;
import org.swtchart.Range;

public class StackedChartViewer extends Page
{
    private static class VehicleBuilder
    {
        private List<Integer> weights = new ArrayList<Integer>();
        private List<SeriesBuilder> series = new ArrayList<SeriesBuilder>();

        public void add(int weight, SeriesBuilder series)
        {
            this.weights.add(weight);
            this.series.add(series);
        }

        public void book(int index, AssetPosition pos)
        {
            long value = pos.getValuation();

            for (int ii = 0; ii < weights.size(); ii++)
                series.get(ii).book(index, value * weights.get(ii) / Classification.ONE_HUNDRED_PERCENT);
        }

    }

    private static class SeriesBuilder
    {
        private TaxonomyNode node;
        private long[] values;
        private boolean hasValues = false;

        public SeriesBuilder(TaxonomyNode node, int size)
        {
            this.node = node;
            this.values = new long[size];
        }

        public boolean hasValues()
        {
            return hasValues;
        }

        public void book(int index, long l)
        {
            hasValues = true;
            values[index] += l;
        }

        public double[] getValues(long[] totals)
        {
            double[] answer = new double[values.length];
            for (int ii = 0; ii < answer.length; ii++)
            {
                if (totals[ii] == 0d)
                    answer[ii] = 0d;
                else
                    answer[ii] = values[ii] / (double) totals[ii];
            }
            return answer;
        }
    }

    private StackedTimelineChart chart;
    private boolean isVisible = false;
    private boolean isDirty = true;

    private List<DateMidnight> dates;

    public StackedChartViewer(PortfolioPart part, TaxonomyModel model, TaxonomyNodeRenderer renderer)
    {
        super(model, renderer);

        Interval interval = part.loadReportingPeriods().getFirst().toInterval();

        Period weekly = Aggregation.Period.WEEKLY;

        final DateMidnight start = interval.getStart().toDateMidnight();
        final DateMidnight end = interval.getEnd().toDateMidnight();
        DateMidnight current = weekly.getStartDateFor(start);

        dates = new ArrayList<DateMidnight>();
        while (current.isBefore(end))
        {
            dates.add(current);
            current = current.plus(weekly.getPeriod());
        }
        dates.add(end);
    }

    public Control createControl(Composite container)
    {
        Composite composite = new Composite(container, SWT.NONE);
        composite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
        composite.setLayout(new FillLayout());

        chart = new StackedTimelineChart(composite, dates);
        chart.getTitle().setVisible(false);

        chart.getLegend().setPosition(SWT.BOTTOM);
        chart.getLegend().setVisible(true);

        chart.getAxisSet().getYAxis(0).getTick().setFormat(new DecimalFormat("#0.0%")); //$NON-NLS-1$

        return composite;
    }

    @Override
    public void nodeChange(TaxonomyNode node)
    {
        isDirty = true;

        if (isVisible)
            asyncUpdateChart();
    }

    @Override
    public void beforePage()
    {
        isVisible = true;

        if (isDirty)
            asyncUpdateChart();
    }

    @Override
    public void afterPage()
    {
        isVisible = false;
    }

    private void asyncUpdateChart()
    {
        new Job(Messages.JobLabelUpdateStackedLineChart)
        {
            @Override
            protected IStatus run(IProgressMonitor monitor)
            {
                updateChart();

                return Status.OK_STATUS;
            }

        }.schedule();
    }

    private void updateChart()
    {
        final Map<InvestmentVehicle, VehicleBuilder> vehicle2builder = new HashMap<InvestmentVehicle, VehicleBuilder>();
        final Map<TaxonomyNode, SeriesBuilder> node2series = new HashMap<TaxonomyNode, SeriesBuilder>();

        getModel().visitAll(new NodeVisitor()
        {
            @Override
            public void visit(TaxonomyNode node)
            {
                if (node.isClassification())
                {
                    node2series.put(node, new SeriesBuilder(node, dates.size()));
                }
                else
                {
                    InvestmentVehicle vehicle = node.getAssignment().getInvestmentVehicle();

                    VehicleBuilder builder = vehicle2builder.get(vehicle);
                    if (builder == null)
                    {
                        builder = new VehicleBuilder();
                        vehicle2builder.put(vehicle, builder);
                    }

                    builder.add(node.getWeight(), node2series.get(node.getParent()));
                }
            }
        });

        final long[] totals = new long[dates.size()];

        int index = 0;
        for (DateMidnight current : dates)
        {
            ClientSnapshot snapshot = ClientSnapshot.create(getModel().getClient(), current.toDate());
            totals[index] = snapshot.getAssets();

            Map<InvestmentVehicle, AssetPosition> p = snapshot.getPositionsByVehicle();

            for (Map.Entry<InvestmentVehicle, VehicleBuilder> entry : vehicle2builder.entrySet())
            {
                AssetPosition pos = p.get(entry.getKey());
                if (pos != null)
                    entry.getValue().book(index, pos);
            }

            index++;
        }

        final List<SeriesBuilder> series = new ArrayList<SeriesBuilder>();
        for (SeriesBuilder s : node2series.values())
        {
            if (s.hasValues())
                series.add(s);
        }

        Collections.sort(series, new Comparator<SeriesBuilder>()
        {
            @Override
            public int compare(SeriesBuilder o1, SeriesBuilder o2)
            {
                long l1 = o1.values[o1.values.length - 1];
                long l2 = o2.values[o2.values.length - 1];
                return l1 > l2 ? -1 : l1 < l2 ? 1 : 0;
            }
        });

        Display.getDefault().asyncExec(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    chart.suspendUpdate(true);
                    for (ISeries s : chart.getSeriesSet().getSeries())
                        chart.getSeriesSet().deleteSeries(s.getId());

                    for (SeriesBuilder serie : series)
                    {
                        chart.addSeries(serie.node.getClassification().getPathName(false), //
                                        serie.getValues(totals), //
                                        getRenderer().getColorFor(serie.node));
                    }

                    chart.getAxisSet().adjustRange();
                    chart.getAxisSet().getYAxis(0).setRange(new Range(-0.01, 1.01));
                }
                finally
                {
                    chart.suspendUpdate(false);
                    chart.redraw();
                }

                isDirty = false;
            }
        });
    }

}
TOP

Related Classes of name.abuchen.portfolio.ui.views.taxonomy.StackedChartViewer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.