2012-01-24 6 views
1

JFreechartで曲線をプロットします。次に、マウスをドラッグして範囲を描画することができます。これらは、AbstractChartAnnotationを使って塗りつぶされたPath2Dを描画します。今のところすごくいいです - すべてが曲線と完全に揃っています。Jfreechartアノテーションが消える

エリアに既にアノテーションが設定されていると、新しいアノテーションが削除されます。私は新しい注釈にXYPlot.removeAnnotationを使用します。

私の問題は、「新しい」注釈が削除されるだけでなく、プロット内の別の注釈も削除されることがあるということです。それはランダムには見えません - 私はちょっとこのようなことが起きやすい "正しい"側の注釈を見つけました。

私はこれを引き起こす可能性が非常に混乱しています。新しい注釈を描画/削除するオブジェクトは毎回回復し、現在の注釈のみを保持します。したがって、他の注釈をどのように削除できますか?

ありがとうございました。ありがとうございました。


提案したように、私はsscceの例を用意します。残念ながら、それはあまりにも短くはありません。

import java.awt.*; 
import java.awt.event.MouseEvent; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Line2D; 
import java.awt.geom.Point2D; 
import java.awt.geom.Rectangle2D; 
import java.util.*; 
import java.util.List; 
import javax.swing.JFrame; 
import javax.swing.event.MouseInputListener; 
import org.jfree.chart.ChartFactory; 
import org.jfree.chart.ChartPanel; 
import org.jfree.chart.JFreeChart; 
import org.jfree.chart.annotations.AbstractXYAnnotation; 
import org.jfree.chart.axis.ValueAxis; 
import org.jfree.chart.plot.Plot; 
import org.jfree.chart.plot.PlotOrientation; 
import org.jfree.chart.plot.PlotRenderingInfo; 
import org.jfree.chart.plot.XYPlot; 
import org.jfree.data.time.Millisecond; 
import org.jfree.data.time.TimeSeries; 
import org.jfree.data.time.TimeSeriesCollection; 
import org.jfree.data.time.TimeSeriesDataItem; 
import org.jfree.ui.RectangleEdge; 

/** 
* 
* @author c.ager 
*/ 
public class IntegrationSSCE { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     JFrame jFrame = new JFrame(); 
     jFrame.setLayout(new BorderLayout()); 
     jFrame.setSize(600, 400); 
     jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE); 
     TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); 
     TimeSeries timeSeries = new TimeSeries("test"); 
     for (long i = 0; i < 1000; i++) { 
      double val = Math.random() + 3 * Math.exp(-Math.pow(i - 300, 2)/1000); 
      timeSeries.add(new Millisecond(new Date(i)), val); 
     } 
     timeSeriesCollection.addSeries(timeSeries); 

     JFreeChart chart = ChartFactory.createTimeSeriesChart(
       null, 
       null, "data", timeSeriesCollection, 
       true, true, false); 
     ChartPanel chartPanel = new ChartPanel(chart); 
     chartPanel.removeMouseListener(chartPanel); 

     Set<MyAnnot> annotSet = new TreeSet<MyAnnot>(); 

     AnnotListener list = new AnnotListener(chartPanel, annotSet, timeSeries); 
     chartPanel.addMouseListener(list); 
     chartPanel.addMouseMotionListener(list); 

     jFrame.add(chartPanel, BorderLayout.CENTER); 


     jFrame.setVisible(true); 

     // TODO code application logic here 
    } 

    private static class AnnotListener implements MouseInputListener { 

     Point2D start, end; 
     MyAnnot currAnnot; 
     final Set<MyAnnot> annotSet; 
     final ChartPanel myChart; 
     final TimeSeries timeSeries; 

     public AnnotListener(ChartPanel myChart, Set<MyAnnot> annotSet, TimeSeries timeSeries) { 
      this.myChart = myChart; 
      this.annotSet = annotSet; 
      this.timeSeries = timeSeries; 
     } 

     @Override 
     public void mousePressed(MouseEvent e) { 
      start = convertScreePoint2DataPoint(e.getPoint()); 
      currAnnot = new MyAnnot(start, timeSeries, myChart.getChart().getXYPlot()); 
      myChart.getChart().getXYPlot().addAnnotation(currAnnot); 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      end = convertScreePoint2DataPoint(e.getPoint()); 
      currAnnot.updateEnd(end); 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      boolean test = annotSet.add(currAnnot); 
      if (!test) { 
       myChart.getChart().getXYPlot().removeAnnotation(currAnnot); 
      } 
     } 

     @Override 
     public void mouseEntered(MouseEvent e) { 
     } 

     @Override 
     public void mouseClicked(MouseEvent e) { 
     } 

     @Override 
     public void mouseExited(MouseEvent e) { 
     } 

     @Override 
     public void mouseMoved(MouseEvent e) { 
     } 

     protected Point2D convertScreePoint2DataPoint(Point in) { 
      Rectangle2D plotArea = myChart.getScreenDataArea(); 
      XYPlot plot = (XYPlot) myChart.getChart().getPlot(); 
      double x = plot.getDomainAxis().java2DToValue(in.getX(), plotArea, plot.getDomainAxisEdge()); 
      double y = plot.getRangeAxis().java2DToValue(in.getY(), plotArea, plot.getRangeAxisEdge()); 
      return new Point2D.Double(x, y); 
     } 
    } 

    private static class MyAnnot extends AbstractXYAnnotation implements Comparable<MyAnnot> { 

     Long max; 
     Line2D line; 
     final TimeSeries timeSeries; 
     final XYPlot plot; 
     final Stroke stroke = new BasicStroke(1.5f); 

     public MyAnnot(Point2D start, TimeSeries timeSeries, XYPlot plot) { 
      this.plot = plot; 
      this.timeSeries = timeSeries; 

      line = new Line2D.Double(start, start); 
      findMax(); 
     } 

     public void updateEnd(Point2D end) { 
      line.setLine(line.getP1(), end); 
      findMax(); 
      fireAnnotationChanged(); 
     } 

     @Override 
     public void draw(Graphics2D gd, XYPlot xyplot, Rectangle2D rd, ValueAxis va, ValueAxis va1, int i, PlotRenderingInfo pri) { 
      PlotOrientation orientation = plot.getOrientation(); 
      RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
        plot.getDomainAxisLocation(), orientation); 
      RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
        plot.getRangeAxisLocation(), orientation); 

      double m02 = va.valueToJava2D(0, rd, domainEdge); 
      // y-axis translation 
      double m12 = va1.valueToJava2D(0, rd, rangeEdge); 
      // x-axis scale 
      double m00 = va.valueToJava2D(1, rd, domainEdge) - m02; 
      // y-axis scale 
      double m11 = va1.valueToJava2D(1, rd, rangeEdge) - m12; 

      Shape s = null; 
      if (orientation == PlotOrientation.HORIZONTAL) { 
       AffineTransform t1 = new AffineTransform(
         0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f); 
       AffineTransform t2 = new AffineTransform(
         m11, 0.0f, 0.0f, m00, m12, m02); 
       s = t1.createTransformedShape(line); 
       s = t2.createTransformedShape(s); 
      } else if (orientation == PlotOrientation.VERTICAL) { 
       AffineTransform t = new AffineTransform(m00, 0, 0, m11, m02, m12); 
       s = t.createTransformedShape(line); 
      } 
      gd.setStroke(stroke); 
      gd.setPaint(Color.BLUE); 
      gd.draw(s); 
      addEntity(pri, s.getBounds2D(), i, getToolTipText(), getURL()); 
     } 

     @Override 
     public int compareTo(MyAnnot o) { 
      return max.compareTo(o.max); 
     } 

     private void findMax() { 
      max = (long) line.getP1().getX(); 

      Point2D left, right; 
      if (line.getP1().getX() < line.getP2().getX()) { 
       left = line.getP1(); 
       right = line.getP2(); 
      } else { 
       left = line.getP2(); 
       right = line.getP1(); 
      } 
      Double maxVal = left.getY(); 
      List<TimeSeriesDataItem> items = timeSeries.getItems(); 
      for (Iterator<TimeSeriesDataItem> it = items.iterator(); it.hasNext();) { 
       TimeSeriesDataItem dataItem = it.next(); 
       if (dataItem.getPeriod().getFirstMillisecond() < left.getX()) { 
        continue; 
       } 
       if (dataItem.getPeriod().getFirstMillisecond() > right.getX()) { 
        break; 
       } 
       double curVal = dataItem.getValue().doubleValue(); 
       if (curVal > maxVal) { 
        maxVal = curVal; 
        max = dataItem.getPeriod().getFirstMillisecond(); 
       } 
      } 
     } 
    } 
} 

ここで問題が発生します。画像2と4は、マウスボタンを押している間に撮影されたことに注意してください。

  1. 少数の非重複行を選択する - それは select a few non-overlapping lines enter image description here enter image description here enter image description here enter image description here

あるべきな問題は、私はちょうどデバッガでそれを見てされていません - ArrayList.remove(Object o)はWRONG要素を削除することができますか?私にはあまりありません...

+0

+1例示的なsscce。 – trashgod

答えて

2

注釈が追加されているLayerをご覧ください。例はhereです。当然ながら、あなたが記述した問題を示すsscceは、問題の原因を明らかにするのに役立ちます。

補遺:潜在的な問題の1つは、後者はスーパークラスの実装に(暗黙的に)依存しているようComparableの実装は、equals()と一致ではないということです。一貫した実装が、TreeSetのようにソートされたSetで使用するために必要です。 hashCode()も上書きする必要があります。クラス​​がその一例です。

+0

Okはsscceを作成しました。しかし、層を見つけることができません。私を指摘できますか? – bdecaf

+0

[_Effective Java_](http://java.sun.com/docs/books/effective/)にアクセスできる場合は、項目9と12を参照してください。 – trashgod

+0

ああ - 私たちはどこかに行っています! hashCodeをオーバーライドするだけでは役に立ちませんでしたが、私は 'equals'をオーバーライドするべきメッセージを得ました。この例では"奇妙な "振る舞いは見えません。残念ながら私はあなたが提案する本にアクセスできない。あなたがお勧めする章は何を扱っていますか? – bdecaf

関連する問題