1   package org.opentrafficsim.draw.graphs;
2   
3   import java.awt.event.ActionEvent;
4   import java.awt.event.ActionListener;
5   
6   import javax.swing.JCheckBoxMenuItem;
7   import javax.swing.JPopupMenu;
8   
9   import org.djunits.value.vdouble.scalar.Duration;
10  import org.djunits.value.vdouble.scalar.Length;
11  import org.djunits.value.vdouble.scalar.Time;
12  import org.jfree.chart.JFreeChart;
13  import org.jfree.chart.event.AxisChangeEvent;
14  import org.jfree.chart.event.AxisChangeListener;
15  import org.jfree.chart.plot.XYPlot;
16  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  public abstract class AbstractSpaceTimePlot extends AbstractBoundedPlot
31  {
32  
33      
34      private static final long serialVersionUID = 20181014L;
35  
36      
37      private final Time initialEnd;
38  
39      
40      private boolean autoBoundAxes = true;
41  
42      
43      private boolean virtualAutoBounds = false;
44  
45      
46      private Double fixedDomainRange = null;
47  
48      
49  
50  
51  
52  
53  
54  
55  
56      public AbstractSpaceTimePlot(final String caption, final Duration updateInterval, final OTSSimulatorInterface simulator,
57              final Duration delay, final Time initialEnd)
58      {
59          super(caption, updateInterval, simulator, delay);
60          this.initialEnd = initialEnd;
61      }
62  
63      
64      @Override
65      protected void setChart(final JFreeChart chart)
66      {
67          super.setChart(chart);
68          XYPlot xyPlot = chart.getXYPlot();
69          setLowerRangeBound(0.0);
70          setUpperRangeBound(getEndLocation().si);
71          setLowerDomainBound(0.0);
72          setUpperDomainBound(this.initialEnd.si);
73          setAutoBounds(xyPlot);
74          
75          xyPlot.getDomainAxis().addChangeListener(new AxisChangeListener()
76          {
77              
78              @SuppressWarnings("synthetic-access")
79              @Override
80              public void axisChanged(final AxisChangeEvent event)
81              {
82                  if (!AbstractSpaceTimePlot.this.virtualAutoBounds)
83                  {
84                      
85                      AbstractSpaceTimePlot.this.autoBoundAxes = false;
86                  }
87              }
88          });
89      }
90  
91      
92      @Override
93      protected void addPopUpMenuItems(final JPopupMenu popupMenu)
94      {
95          JCheckBoxMenuItem fixedDomainCheckBox = new JCheckBoxMenuItem("Fix time range", false);
96          fixedDomainCheckBox.addActionListener(new ActionListener()
97          {
98              
99              @SuppressWarnings("synthetic-access")
100             @Override
101             public void actionPerformed(final ActionEvent e)
102             {
103                 boolean fix = ((JCheckBoxMenuItem) e.getSource()).isSelected();
104                 AbstractSpaceTimePlot.this.fixedDomainRange =
105                         fix ? getChart().getXYPlot().getDomainAxis().getRange().getLength() : null;
106                 notifyPlotChange();
107             }
108         });
109         popupMenu.insert(fixedDomainCheckBox, 0);
110         popupMenu.insert(new JPopupMenu.Separator(), 1);
111     }
112 
113     
114     @Override
115     protected void update()
116     {
117         if (getUpdateTime() != null && this.initialEnd != null)
118         {
119             setUpperDomainBound(Math.max(getUpdateTime().si, this.initialEnd.si));
120         }
121         if (this.autoBoundAxes && getChart() != null) 
122         {
123             setAutoBounds(getChart().getXYPlot());
124         }
125         super.update();
126     }
127 
128     
129 
130 
131 
132 
133     private void setAutoBounds(final XYPlot plot)
134     {
135         
136         
137         this.virtualAutoBounds = true;
138         if (this.fixedDomainRange != null && getUpdateTime().si > 0.0)
139         {
140             plot.getDomainAxis().setRange(Math.max(getUpdateTime().si - this.fixedDomainRange, 0.0), getUpdateTime().si);
141         }
142         else
143         {
144             super.setAutoBoundDomain(plot); 
145         }
146         super.setAutoBoundRange(plot); 
147         this.virtualAutoBounds = false;
148     }
149 
150     
151     @Override
152     protected final void setAutoBoundDomain(final XYPlot plot)
153     {
154         super.setAutoBoundDomain(plot);
155         this.autoBoundAxes = true;
156     }
157 
158     
159     @Override
160     protected final void setAutoBoundRange(final XYPlot plot)
161     {
162         super.setAutoBoundRange(plot);
163         this.autoBoundAxes = true;
164     }
165 
166     
167 
168 
169 
170     protected abstract Length getEndLocation();
171 
172 }