Package com.amper.graph

Source Code of com.amper.graph.SimpleGraph$sliderChangeListener

package com.amper.graph;

import java.awt.*;
import java.awt.geom.GeneralPath;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.text.SimpleDateFormat;
import java.util.SimpleTimeZone;
import java.text.Format;
import java.awt.event.InputEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.io.*;


/** Very simple and easy graph class
* @author de-nos
*
*/
/**
* @author de-nos
*
*/
@SuppressWarnings("serial")
public class SimpleGraph extends JPanel{
    private Series series;
    private Gridline gridx;
    private Gridline gridy;
    private static final int INDENT_TOP = 0;
    private static final int INDENT_RIGHT = 1;
    private static final int INDENT_BOTTOM = 2;
    private static final int INDENT_LEFT = 3;
    private int plot_indent[] = {5, 5, 14, 5};
    private int plot_x = plot_indent[INDENT_LEFT];
    private int plot_y = plot_indent[INDENT_BOTTOM];
    private int plot_w = 20;
    private int plot_h = 10;
    private double domain_indent;// = (domain_end - domain_begin) / 20;
    private int MAX_NUMBER_OF_GRIDLINES = 21;
    private int MAX_NUMBER_OF_GRIDLINES_Y = 11;
    private int max_text_width = 0// максимальная ширина текстовых меток по оси Y
    private boolean auto_scroll_enabled = false;
    private JSlider domain_slider;
    private boolean needToRedraw = false;
    private boolean antialias_enabled = true;
    private DecimalFormat range_stringformat = new DecimalFormat("0");
    private DecimalFormat chooser_stringformat = new DecimalFormat("0.000");
    private Format domain_stringformat;
    private int mouse_x_pos;
    private boolean is_paint_chooser = false;
    private double domain_chooser;
    private boolean filter_enabled = false;
    private double filter_value = 0.1;
    private String[] info = new String[3];

    public static final int FORMAT_DECIMAL = 0;
    public static final int FORMAT_TIME = 1;
    //public static final int FORMAT_DECIMAL_LOG = 2;

    public SimpleGraph(Series series) {
        this(series, FORMAT_DECIMAL);
    }

    public SimpleGraph(Series series, int domain_format) {
        DecimalFormatSymbols dfs = new DecimalFormatSymbols();
        dfs.setDecimalSeparator('.');
        range_stringformat.setDecimalFormatSymbols(dfs);
        chooser_stringformat.setDecimalFormatSymbols(dfs);

        this.series = series;
        gridx = new Gridline(domain_format, MAX_NUMBER_OF_GRIDLINES);
        gridy = new Gridline(Gridline.FORMAT_DECIMAL, MAX_NUMBER_OF_GRIDLINES_Y);
        domain_indent = (gridx.getEnd() - gridx.getBegin()) / 20;
        err = new double[series.getNumberOfSeries()-1];
        series.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Series sr = (Series) e.getSource();
                if (filter_enabled) {
                    applyFilterForLast();
                }
                if (auto_scroll_enabled) {
                    autoScroll();
                } else {
                    // Repaint if new data not behaind the plot
                    double dd[] = sr.getElements(sr.getLength()-2);
                    if (dd != null && dd.length > 0) {
                        if ((dd[0] < gridx.getEnd()) && (dd[0] > gridx.getBegin())) {
                            repaint();
                        }
                    }
                }
                if (sr.getMaxX() - sr.getMinX() + domain_indent*2 < gridx.getRange()) {
                    if (domain_slider != null) domain_slider.setEnabled(false);
                    //setDomain(sr.getMinX() - domain_indent, sr.getMinX() - domain_indent + domain);
                } else {
                    if (domain_slider != null) domain_slider.setEnabled(true);
                    //calcSlider();
                }
                info[0] =  sr.getLength() + "x" + sr.getNumberOfSeries();
            }
        });
        this.addMouseListener(new MouseListener(){
            public void mouseClicked(MouseEvent e) {}
            public void mousePressed(MouseEvent e) {
                mouse_x_pos = e.getX();
                if (e.getModifiersEx() == InputEvent.BUTTON1_DOWN_MASK) {
                    is_paint_chooser = true;
                    domain_chooser = gridx.getBegin() + convertPixelToX(e.getX() - plot_x);
                    repaint();
                }
                if (e.getModifiersEx() == InputEvent.BUTTON2_DOWN_MASK) {
                    //System.out.print("2");
                    domain_slider.setValue(domain_slider.getMaximum());
                    setAutoScroll(true);
                    //savePlot("qq.png");
                }
            }
            public void mouseReleased(MouseEvent e) {
                repaint();
                is_paint_chooser = false;
            }
            public void mouseEntered(MouseEvent e) {}
            public void mouseExited(MouseEvent e) {}
        });
        this.addMouseWheelListener(new MouseWheelListener(){
            public void mouseWheelMoved(MouseWheelEvent e) {
                if (e.getWheelRotation() > 0) {
                    zoomOutDomain();
                }
                if (e.getWheelRotation() < 0) {
                    zoomInDomain();
                }
                //System.out.print("w:" + e.getWheelRotation() + " ");

            }
        });
        this.addMouseMotionListener(new MouseMotionListener(){
            public void mouseDragged(MouseEvent e) {
                if (e.getModifiersEx() == InputEvent.BUTTON3_DOWN_MASK) {
                    setAutoScroll(false);
                    double x = gridx.getBegin() + convertPixelToX(mouse_x_pos - e.getX());
                    //setDomain(x, x + gridx.getRange());
                    shiftDomainByBegin(x);
                }
                if (is_paint_chooser) {
                    domain_chooser = gridx.getBegin() + convertPixelToX(e.getX() - plot_x);
                    repaint();
                }
                mouse_x_pos = e.getX();

            }
            public void mouseMoved(MouseEvent e) {}
        });
        (new Thread() {
            public void run() {
                while(true) {
                    if (needToRedraw) {
                        redraw();
                        needToRedraw = false;
                    }
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }).start();
    }

    public void savePlotToPNG(String filename) {
        BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        this.paint(g);
        g.dispose();

        File file = new File(filename);
        try {
            javax.imageio.ImageIO.write(image, "png", file);
            //System.out.println("Image is saved in file: " + filename);
        } catch (IOException ex) {
        }
    }

    private double err[];

    // Применение фильтра к последним добавленным элементам
    private void applyFilterForLast() {
        applyFilterByIndex(series.getLength() - 2, err);
    }

    // Применение фильтра к элементу с номером index.
    private double[] applyFilterByIndex(int index, double e[]) {
        if (series.getLength() < 3) return null;
        if (index < 0) return null;
        if (index > series.getLength()-1) return null;
        boolean bb[] = new boolean[series.getNumberOfSeries()];
        if (index == 0 || index == series.getLength()-1) {
            for (int i = 0; i < series.getNumberOfSeries(); i++) {
                bb[i] = true;
                series.setElementsFlags(index, bb);
            }
            return null;
        }
        double dd[] = getAngle(series.getElements(index - 1),
                               series.getElements(index),
                               series.getElements(index + 1));
        bb[0] = true;
        if (e == null || e.length < series.getNumberOfSeries()-1) {
            e = new double[series.getNumberOfSeries()-1];
        }
        for (int i = 1; i < series.getNumberOfSeries(); i++) {
            if (Math.abs(dd[i-1]) > filter_value) {
                bb[i] = true;
            } else {
                e[i-1] += dd[i-1];
                if (Math.abs(e[i-1]) > filter_value) {
                    bb[i] = true;
                    e[i-1] = 0;
                } else {
                    bb[i] = false;
                }
            }
        }
        series.setElementsFlags(index, bb);
        return e;
    }

    // Применение фильтра ко всем элементам
  private void applyFilterForAll() {
        double e[] = null;
        for (int i = 0; i < series.getLength(); i++) {
            e = applyFilterByIndex(i, e);
        }
    }

    // Возвращает угловую разницу отрезков (p1[i];p2[i]) и (p2[i];p3[i])
    private double[] getAngle(double[] p1, double[] p2, double[] p3) {
        if ((p1.length < series.getNumberOfSeries()) ||
            (p2.length < series.getNumberOfSeries()) ||
            (p3.length < series.getNumberOfSeries())) return new double[0];
        double res[] = new double[series.getNumberOfSeries()-1];
        double x1, x2, x3;
        x1 = p1[0];
        x2 = p2[0];
        x3 = p3[0];
        for (int i = 1; i < series.getNumberOfSeries(); i++ ) {
            res[i-1] = Math.atan(((p2[i] - p1[i])/(x2 - x1) - (p3[i] - p2[i])/(x3 - x2))*gridx.getRange()/(gridy.getEnd()-gridy.getBegin())) * 180 / Math.PI;
        }

        return res;
    }

    private void redraw(){
        int value = domain_slider.getValue();
        if (value == domain_slider.getMaximum()) {
            setAutoScroll(true);
        } else {
            setAutoScroll(false);
            int slider_steps = domain_slider.getMaximum() - domain_slider.getMinimum();
            double x = (series.getMaxX() - series.getMinX() - gridx.getRange() +
                        domain_indent * 2) /
                       slider_steps * value + series.getMinX() -
                       domain_indent;

            shiftDomainByBegin(x);
        }

    }

    public void setDomainSlider(JSlider slider) {
        domain_slider = slider;
        domain_slider.addChangeListener(new sliderChangeListener());
        if (domain_slider.getValue() == domain_slider.getMaximum()) {
            setAutoScroll(true);
        } else {
            setAutoScroll(false);
        }
    }

    class sliderChangeListener implements ChangeListener {
        public void stateChanged(ChangeEvent e) {
            needToRedraw = true;
        }
    }


    private void autoScroll() {
        if (series.getMaxX() - series.getMinX() + domain_indent*2 >= gridx.getRange()) {
          shiftDomainByBegin(series.getMaxX() + domain_indent - gridx.getRange());
        } else {
          shiftDomainByBegin(series.getMinX() - domain_indent);
        }
    }

    public void setAutoScroll(boolean enabled) {
        auto_scroll_enabled = enabled;
        if (auto_scroll_enabled) autoScroll();
    }

    /** Метод позволяет установить отображаемый диапазон графика на оси абсцисс.
     * @param x1 - левая граница отображаемого диапазона.
     * @param x2 - правая граница отображаемого диапазона.
     * Координата x1 должна быть не больше координаты x2.
     */
    public void setDomain(double x1, double x2) {
      gridx.setRange(x1, x2);
        domain_indent = gridx.getRange() / 20;
        if (is_paint_chooser) {
            domain_chooser = gridx.getBegin() + convertPixelToX(mouse_x_pos - plot_x);
        }
        repaint();
       
        if (filter_enabled) applyFilterForAll();
        domain_stringformat = getStringFormat(gridx.getStep());
    }
   
    public void shiftDomainByBegin(double begin) {
      gridx.shiftRangeByBegin(begin);
      repaint();
    }

    private Format getStringFormat(double grid_step) {
        if (gridx.getFormat() == FORMAT_TIME) {  // time format ----------------
            SimpleDateFormat format;
            if (grid_step > 500*60) {
                format = new SimpleDateFormat("HH:mm''");
            } else if (grid_step > 500) {
                format = new SimpleDateFormat("HH:mm''ss''''");
            } else {
                format = new SimpleDateFormat("mm''ss.SSS''''");
            }
            format.setTimeZone(new SimpleTimeZone(0, ""));
            return format;
        //} else if (domain_format == FORMAT_DECIMAL_LOG) {
        } else // decimal and decimal_log formats ---------------
            DecimalFormat format = new DecimalFormat("0.0");
            DecimalFormatSymbols dfs = new DecimalFormatSymbols();
            dfs.setDecimalSeparator('.');
            format.setDecimalFormatSymbols(dfs);
            if (gridx.getStep() >= 1) {
                format.setMaximumFractionDigits(0);
            } else {
              //System.out.println("gdln " + gridline_step);
                int digs = (int) Math.ceil(Math.abs(Math.log10(gridx.getStep())));
                //digs++;
                format.setMaximumFractionDigits(digs);
                format.setMinimumFractionDigits(digs);
            }
            return format;
        }
    }
   
    /** Возвращает ранг заданного значения val. Рангом считается значимость при отображении на
     * графике (например, значение "100" более значимое чем "120" или "80", поскольку на графике лучше
     * будет отобразить штрих и подпись со значением "100" нежели со значением "120" или "80").
     * @param val - заданное значение из некоторого диапазона.
     * @param step - минимальный шаг штрихов
     * @param factor - коэффициент шага, фактически это первая значимая цифра минимального шага штрихов (step).
     * @return ранг заданного числа.
     */
    private static int getRang(double val, double step, int factor) {
      double d = Math.round(val / step * factor);
      int k;
     
      for (int i = idec.length - 1; i >= 0; i--) {
        k = idec[i];
        if (d % k == 0) return k;
      }
      return 1;
    }
   
    public double[] getDomain() {
        return new double[] {gridx.getBegin(), gridx.getEnd()};
    }

    public void setRange(double y1, double y2) {
      gridy.setRange(y1, y2);
        repaint();
    }

    public void update(Graphics g) {
    }

    private void calcPlotBaunds(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        max_text_width = (int)getMaxTextWidth(g2d, gridy.getSteps());

        plot_x = plot_indent[INDENT_LEFT] + max_text_width;
        plot_y = plot_indent[INDENT_TOP];
        plot_w = getSize().width - plot_indent[INDENT_LEFT] - max_text_width - plot_indent[INDENT_RIGHT];
        plot_h = getSize().height - plot_indent[INDENT_TOP] - plot_indent[INDENT_BOTTOM];
    }

    public void paint (Graphics g)  {
        super.paint(g);
        long time = System.currentTimeMillis();
        Graphics2D g2d = (Graphics2D) g;
        if (antialias_enabled) {
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                 RenderingHints.VALUE_ANTIALIAS_ON);
        }
        calcPlotBaunds(g);
        paintGridlines(g2d);
        paintData(g2d);
        paintFrame(g2d);
        paintChoosers(g2d);

        time = System.currentTimeMillis() - time;
        debug_filterTime(time);
        info[2] = String.valueOf((long)(1000/debug_time)) + " fps";

        paintInfo(g2d);
        //System.out.println("Draw time in mills: " + time);
    }

    private void paintInfo(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setFont(new Font("Verdana", Font.PLAIN, 10));
        for (int i = 0; i < info.length; i++) {
            if (info[i] == null) continue;
            int wdt = (int)getTextWidth(g2d, info[i]);
            g2d.setColor(new Color(0.9f, 0.9f, 0.9f, 0.7f));
            g2d.fill(new java.awt.geom.RoundRectangle2D.Double(
                    plot_x + plot_w - wdt - 5 - 1,
                    plot_y + 12 + i*12 + 2 - 11,
                    wdt+2, 11, 4, 4));
            g2d.setColor(Color.GRAY);
            g2d.drawString(info[i],
                           plot_x + plot_w - wdt - 5,
                           plot_y + 12 + i*12);
        }
    }

    private double debug_time = 0;
    private int KALMAN_LENGTH = 10;
    private void debug_filterTime(long time) {
        //if (Math.abs(debug_time - time) > 20) debug_time = time;
        debug_time = debug_time - debug_time/KALMAN_LENGTH + (double)time/KALMAN_LENGTH;
    }

    private static int idec[] = new int[]{1, 2, 5, 10, 20, 50, 100};
    private static final int SIGNATURES_GAP = 10;
    private void paintGridlines(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        // -----------------------------------------------------------------------------------------
        // domain gridlines and signatures
        double wdt, wdt2;          // ширина текущей подписи и следующей 
        //double x = (Math.ceil(domain_begin/gridline_step))*gridline_step;  // координата рисуемого штриха
        double x1;                 // x-пиксел рисуемого штриха
        String sval, sval2;        // текст текущей и следующей подписей
        double step_len_pix = gridx.getStep() / gridx.getRange() * plot_w;  // gridline_step в пикселах
        int xleft;                 // левая  граница текущей подписи
        long dev = 1;
        double steps[];
       
        if (gridx.getType() == Gridline.FORMAT_DECIMAL) {
          if (gridx.getRange() > 20000000) { /** @todo доделать*/
            dev = 1000000;
          } else if (gridx.getRange() > 20000) {
            dev = 1000;
          }
        }
        steps = gridx.getSteps();
        /* Нахождение наиболее широкой (в пикселах) подписи */ {
          sval = domain_stringformat.format(steps[0]/dev);
          wdt = g2d.getFont().getStringBounds(sval, g2d.getFontRenderContext()).getWidth();
          sval2 = domain_stringformat.format(steps[steps.length-1]/dev);
          wdt2 = g2d.getFont().getStringBounds(sval2, g2d.getFontRenderContext()).getWidth();
          if (wdt < wdt2) wdt = wdt2;
        }
        //System.out.println("wdt: " + wdt);
       
        int i = 0;
        for (; i < idec.length; i++) {
          if (gridx.getFactor() > idec[i]) continue;
            if (wdt < step_len_pix/gridx.getFactor()*idec[i] - SIGNATURES_GAP) {
              break;
            }
        }
        if (i == idec.length) i = idec.length-1;
       
        for(int k = 0; k < steps.length; k++) {
            x1 = plot_x + (steps[k]-gridx.getBegin())/gridx.getRange()*plot_w;
          int rang = getRang(steps[k], gridx.getStep(), gridx.getFactor());
           
            /*draw gridlines (штрихи)*/ {
              if (rang >= 100) {
                    g2d.setColor(Color.DARK_GRAY);
              } else if (rang >= 10) {
                    g2d.setColor(Color.GRAY);
              } else {
                    g2d.setColor(Color.LIGHT_GRAY);
              }
                g2d.drawLine((int) x1, plot_y, (int) x1, plot_y + plot_h);
            }
           
            /*draw signatures (подписи)*/ {
              if (rang >= idec[i] && (!(idec[i] == 2 && rang == 5) && !(idec[i] == 20 && rang == 50))) {
                  sval = domain_stringformat.format(steps[k]/dev);
                    wdt = g2d.getFont().getStringBounds(sval, g2d.getFontRenderContext()).getWidth();
                    xleft = (int)(x1 - wdt / 2);
                g2d.setColor(Color.GRAY);
                g2d.drawString(sval, xleft, plot_y + plot_h + 12);
              }
              if (dev > 1) {  // вывод множителя на график
                g2d.setColor(Color.GRAY);
                sval = "x" + Long.toString(dev);
                    wdt = g2d.getFont().getStringBounds(sval, g2d.getFontRenderContext()).getWidth();
                g2d.drawString(sval, plot_x + plot_w - (int)wdt - 3, plot_y + plot_h - 4);
              }
            }
        }

        // -----------------------------------------------------------------------------------------
        // range gridlines and signatures
        double y1;

        steps = gridy.getSteps();
        //double max_text_width = getMaxTextBounds(g2d, steps).getWidth();
        for(int k = 0; k < steps.length; k++) {
            y1 = plot_y + plot_h - (steps[k]-gridy.getBegin())/gridy.getRange()*plot_h;
            // draw gridline
            {
                g2d.setColor(Color.LIGHT_GRAY);
                g2d.drawLine(plot_x, (int) y1, plot_x + plot_w, (int) y1);
            }
            // draw signatures
            {
                wdt = (int)getTextWidth(g2d, range_stringformat.format(steps[k]));
                g2d.setColor(Color.GRAY);
                g2d.drawString(range_stringformat.format(steps[k]), (int) (plot_x - wdt - 2), (int) (y1 + 4));
            }
        }

    }

    /*private Dimension getMaxTextBounds(Graphics2D g2d, double arr[]) {
        if (arr.length == 0) return new Dimension(0, 0);
        int width, height;
        width =  Math.max((int)getTextWidth(g2d, arr[0]), (int)getTextWidth(g2d, arr[arr.length-1]));
        height =  Math.max((int)getTextHeight(g2d, arr[0]), (int)getTextHeight(g2d, arr[arr.length-1]));
        return new Dimension(width, height);
    }*/

    private double getMaxTextWidth(Graphics2D g2d, double arr[]) {
        if (arr.length == 0) return 0;
        return Math.max(getTextWidth(g2d, range_stringformat.format(arr[0])),
                        getTextWidth(g2d, range_stringformat.format(arr[arr.length-1])));
    }
    /*private double getMaxTextHeight(Graphics2D g2d, double arr[]) {
        if (arr.length == 0) return 0;
        return Math.max(getTextHeight(g2d, range_stringformat.format(arr[0])),
                        getTextHeight(g2d, range_stringformat.format(arr[arr.length-1])));
    }*/

    private double getTextWidth(Graphics2D g2d, String text) {
        return g2d.getFont().getStringBounds(text, g2d.getFontRenderContext()).getWidth();
    }
    /*private double getTextHeight(Graphics2D g2d, String text) {
        return g2d.getFont().getStringBounds(text, g2d.getFontRenderContext()).getHeight();
    }*/

    private void paintFrame(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
                                      BasicStroke.JOIN_MITER));
        g2d.setColor(Color.BLACK);
        //g2d.setColor(UIManager.getColor("TitledBorder.titleColor"));
        g2d.draw(new Rectangle(plot_x, plot_y, plot_w, plot_h));
    }



    private void paintData(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        int point_count = 0;
        int point_all_count = 0;
        int number_of_series = series.getNumberOfSeries();
        g2d.setStroke(new BasicStroke(series.getLinesWidth(), BasicStroke.CAP_BUTT,
                                      BasicStroke.JOIN_MITER));
        GeneralPath polyLines[] = new GeneralPath[number_of_series-1];
        for (int j = 0; j < number_of_series-1; j++) {
            polyLines[j] = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 1);
        }
        int index_begin = series.getIndex(gridx.getBegin());
        int index_end = series.getIndex(gridx.getEnd());
        if (index_begin > 0) index_begin--;
        //System.out.println(index_begin + " " + index_end);
        if (series.getLength() > 1) {
            float tx, ty;
            for (int j = 0; j < number_of_series-1; j++) {
                tx = calcTX(index_begin, 0);
                ty = calcTY(index_begin, j+1);
                //angles_err[j] = 0;
                polyLines[j].moveTo(tx, ty);
                point_count++;
                point_all_count++;
            }
            boolean bb[];
            for (int i = index_begin + 1; i <= index_end; i++) {
                bb = series.getElementsFlags(i);
                for (int j = 0; j < number_of_series-1; j++) {
                    if (filter_enabled) {
                        if (!bb[j + 1] && i < index_end) {
                            point_all_count++;
                            continue;
                        }
                    }
                    tx = calcTX(i, 0);
                    ty = calcTY(i, j+1);
                    polyLines[j].lineTo(tx, ty);
                    //g2d.drawLine((int)tx, (int)ty, (int)tx, (int)ty);
                    point_count++;
                    point_all_count++;
                }
            }
            Shape shape = g2d.getClip();
            g2d.setClip(plot_x+1, plot_y+1, plot_w-1, plot_h-1);
            for (int j = 0; j < number_of_series-1; j++) {
                g2d.setColor(series.getColor(j));
                g2d.draw(polyLines[j]);
            }
            info[1] = String.valueOf(point_count) + "/" + String.valueOf(point_all_count) + " points";
            g2d.setClip(shape);
        }
    }

    // Возвращает наклон отрезка в градусах
    /*private float getAngle(float x1, float y1, float x2, float y2) {
        return (float)Math.atan((y2 - y1)/(x2 - x1)) * 180 / (float)Math.PI;
    }*/

    // Прорисовка дополнительной информации (вертикальной черты и значений графиков)
    private void paintChoosers(Graphics g) {
        if (!is_paint_chooser) return;
        Graphics2D g2d = (Graphics2D) g;
        g2d.setStroke(new BasicStroke(series.getLinesWidth(), BasicStroke.CAP_BUTT,
                                      BasicStroke.JOIN_MITER));
        g2d.setFont(new Font("Verdana", Font.BOLD, 12));
        //double dd[] = series.getElements(series.getIndex(domain_chooser));
        double dd[] = getYbyX(domain_chooser);
        double dd_velocity[] = getVelocityByX(domain_chooser);
        if (dd_velocity.length <= 0) return//?? кто это написал

        g2d.setColor(Color.BLACK);
        float x1 = (float)(plot_x + (domain_chooser-gridx.getBegin())/gridx.getRange()*plot_w);
        if ((x1 < plot_x) || (x1 > plot_x + plot_w)) return; // дабы не выходить за границы
        g2d.drawLine((int)x1, plot_y, (int)x1, plot_y + plot_h);
        //g2d.draw(new java.awt.geom.Line2D.Float(x1, plot_y, x1, plot_y + plot_h));

        if (velocity_enable) {
          g2d.setColor(Color.LIGHT_GRAY);
          x1 = (float)(plot_x + (series.getElements(begin)[0]-gridx.getBegin())/gridx.getRange()*plot_w);
          if ((x1 < plot_x) || (x1 > plot_x + plot_w)) {
          } else {
            g2d.drawLine((int) x1, plot_y, (int) x1, plot_y + plot_h);
          }
          x1 = (float)(plot_x + (series.getElements(end)[0]-gridx.getBegin())/gridx.getRange()*plot_w);
          if ((x1 < plot_x) || (x1 > plot_x + plot_w)) {
          } else {
            g2d.drawLine((int) x1, plot_y, (int) x1, plot_y + plot_h);
          }
        }

        //float diam = series.getLinesWidth()*5;
        if (dd.length > 0) {
            String str = domain_stringformat.format(dd[0]);
            if (velocity_enable) {
              str += " (" + chooser_stringformat.format(dd_velocity[0]) + ")";
            }
            int wdt = (int)getTextWidth(g2d, str);
            g2d.setColor(new Color(0.9f, 0.9f, 0.9f, 0.7f));
            g2d.fill(new java.awt.geom.RoundRectangle2D.Double(
                    plot_x + 7 - 2,
                    plot_y + 0*14 + 2,
                    wdt+4, 14, 7, 7));

            g2d.setColor(Color.GRAY);
            g2d.drawString(str, plot_x + 7, plot_y + 14 + 0 * 14);

            for (int i = 1; i < series.getNumberOfSeries(); i++) {
                str = chooser_stringformat.format(dd[i]);
                if (velocity_enable) {
                  str += " (" + chooser_stringformat.format(dd_velocity[i]*velocity_factor) + ")";
                }
                wdt = (int)getTextWidth(g2d, str);
                g2d.setColor(new Color(0.9f, 0.9f, 0.9f, 0.7f));
                g2d.fill(new java.awt.geom.RoundRectangle2D.Double(
                        plot_x + 7 - 2,
                        plot_y + i*14 + 2,
                        wdt+4, 14, 7, 7));

                g2d.setColor(series.getColor(i-1));
                g2d.drawString(str, plot_x + 7, plot_y + 14 + i * 14);

                /*g2d.fillOval((int)Math.round(x1-diam/2),
                             (int)(plot_y + plot_h - ((dd[i] - range_begin) * plot_h/(range_end - range_begin)) - diam/2),
                             (int)diam,
                             (int)diam);*/
            }
        }
    }

    private boolean velocity_enable = false;
    private int velocity_length = 1;
    private double velocity_factor = 1;
    private int begin;
    private int end;
    /** @todo оптимизировать вычисление скорости (наклона кривых) */
    private double[] getVelocityByX(double x) {
        if (series.getLength() <= 0) return new double[0];
        int idx = series.getIndex(domain_chooser);
        begin = idx - velocity_length;
        end = idx + velocity_length - 1;
        if (begin < 0) {
            begin = 0;
        }
        if (end > series.getLength() - 1) {
            end = series.getLength() - 1;
        }
        double dd1[] = series.getElements(begin);
        double dd2[] = series.getElements(end);
        double ret[] = new double[series.getNumberOfSeries()];
        ret[0] = dd2[0] - dd1[0];
        for (int i = 1; i < ret.length; i++) {
            ret[i] = (dd2[i] - dd1[i]) / ret[0];
        }
        return ret;
    }
   
    public void setVelocityEnable(boolean enabled) {
      velocity_enable = enabled;
    }

    // Устанавливает диапазон, по которому измеряется скорость (наклон кривой)
    public void setVelocityLength(int length) {
        velocity_length = length;
    }

    // Устанавливает множитель скорости при отображении на графике
    public void setVelocityFactor(double factor) {
        velocity_factor = factor;
    }


    private double[] getYbyX(double x) {
        int idx = series.getIndex(domain_chooser);
        double dd2[] = series.getElements(idx);
        if (idx == 0) {
            return dd2;
        }

        if (series.getLength() < 2 || x > series.getElements(series.getLength()-1)[0]) {
            return dd2;
        }
        double dd1[] = series.getElements(idx-1);
        double k;
        k = (x - dd1[0]) / (dd2[0] - dd1[0]);
        double ddr[] = new double[dd1.length];
        ddr[0] = x;
        for (int i = 1; i < dd1.length; i++) {
            ddr[i] = dd1[i] + (dd2[i] - dd1[i]) * k;
        }
        return ddr;
    }

    /** Sets minimal and maximal doomain range by zooming
     * @param min_range
     * @param max_range
     */
    public void setZoomBounds(double min_range, double max_range) {
      if (min_range > max_range) return;
      this.min_range = min_range;
      this.max_range = max_range;
    }
   
    private double ZOOM_FACTOR_DOMAIN = 1.1;
    private double max_range = 1000000000000d;
    private double min_range = 0.000001d;
    public void zoomInDomain() {
        double d = (gridx.getRange() - gridx.getRange() / ZOOM_FACTOR_DOMAIN)/2;
        if (gridx.getEnd() - gridx.getBegin() - d * 2 > min_range) {
          setDomain(gridx.getBegin() + d, gridx.getEnd() - d);
        } else {
          setDomain(gridx.getBegin() + gridx.getRange()/2 - min_range/2,
                gridx.getEnd() - gridx.getRange()/2 + min_range/2);
        }
        if (auto_scroll_enabled) autoScroll();
    }
   
    public void zoomOutDomain() {
        double d = (gridx.getRange() - gridx.getRange() * ZOOM_FACTOR_DOMAIN)/2;
        if (gridx.getEnd() - gridx.getBegin() - d * 2 < max_range) {
          setDomain(gridx.getBegin() + d, gridx.getEnd() - d);
        } else {
          setDomain(gridx.getBegin() + gridx.getRange()/2 - max_range/2,
                gridx.getEnd() - gridx.getRange()/2 + max_range/2);
        }
        if (auto_scroll_enabled) autoScroll();
    }

    private double convertXToPixel(double x_unit) {
        double pix_per_xunit = plot_w / gridx.getRange();
        return x_unit * pix_per_xunit;
    }

    private double convertPixelToX(double pix) {
        double pix_per_xunit = plot_w / gridx.getRange();
        return pix / pix_per_xunit;
    }

    private float calcTX(int i, int j) {
      //if (domain_format == FORMAT_DECIMAL_LOG) {
      //  return (float) (plot_x + Math.log10(convertXToPixel(series.getElements(i)[j] - domain_begin))*plot_w/Math.log10(plot_w));
      //} else {
        return (float) (plot_x + convertXToPixel(series.getElements(i)[j] - gridx.getBegin()));
      //}
    }

    private float calcTY(int i, int j) {
        return (float) (plot_y + plot_h - (series.getElements(i)[j] - gridy.getBegin())
                        / (gridy.getEnd() - gridy.getBegin()) * plot_h);
    }

    public void setAntialiasing(boolean enabled) {
        antialias_enabled = enabled;
    }

    public void setFilterEnable(boolean enabled) {
        filter_enabled = enabled;
    }
    public void setFilterValue(double value) {
        filter_value = value;
    }

}
TOP

Related Classes of com.amper.graph.SimpleGraph$sliderChangeListener

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.