1
2
3
4 package org.opentrafficsim.swing.graphs;
5
6 import java.awt.BasicStroke;
7 import java.awt.Color;
8 import java.awt.Font;
9 import java.awt.event.ActionEvent;
10 import java.awt.event.ActionListener;
11 import java.util.List;
12
13 import javax.swing.ButtonGroup;
14 import javax.swing.JMenu;
15 import javax.swing.JPopupMenu;
16 import javax.swing.JRadioButtonMenuItem;
17
18 import org.djunits.value.vdouble.scalar.Duration;
19 import org.jfree.chart.ChartMouseEvent;
20 import org.jfree.chart.ChartMouseListener;
21 import org.jfree.chart.annotations.XYAnnotation;
22 import org.jfree.chart.annotations.XYLineAnnotation;
23 import org.jfree.chart.annotations.XYTextAnnotation;
24 import org.jfree.chart.entity.AxisEntity;
25 import org.jfree.chart.entity.XYItemEntity;
26 import org.jfree.chart.ui.TextAnchor;
27 import org.jfree.data.Range;
28 import org.opentrafficsim.draw.graphs.FundamentalDiagram;
29 import org.opentrafficsim.draw.graphs.FundamentalDiagram.Quantity;
30 import org.opentrafficsim.draw.graphs.GraphUtil;
31
32
33
34
35
36
37
38
39 public class SwingFundamentalDiagram extends SwingPlot
40 {
41
42
43 private static final long serialVersionUID = 20190823L;
44
45
46
47
48
49 public SwingFundamentalDiagram(final FundamentalDiagram plot)
50 {
51 super(plot);
52 }
53
54
55 @Override
56 protected ChartMouseListener getChartMouseListener()
57 {
58 ChartMouseListener toggle = !getPlot().hasLineFD() && getPlot().getSource().getNumberOfSeries() < 2 ? null : GraphUtil
59 .getToggleSeriesByLegendListener(getPlot().getLegend(), getPlot().getLaneVisible());
60 return new ChartMouseListener()
61 {
62
63 @SuppressWarnings("unchecked")
64 @Override
65 public void chartMouseClicked(final ChartMouseEvent event)
66 {
67 if (toggle != null)
68 {
69 toggle.chartMouseClicked(event);
70 }
71
72 for (XYAnnotation annotation : ((List<XYAnnotation>) getPlot().getChart().getXYPlot().getAnnotations()))
73 {
74 if (annotation instanceof XYLineAnnotation)
75 {
76 getPlot().getChart().getXYPlot().removeAnnotation(annotation);
77 }
78 }
79
80 if (event.getEntity() instanceof XYItemEntity)
81 {
82 XYItemEntity itemEntity = (XYItemEntity) event.getEntity();
83 int series = itemEntity.getSeriesIndex();
84 for (int i = 0; i < getPlot().getItemCount(series) - 1; i++)
85 {
86 XYLineAnnotation annotation = new XYLineAnnotation(getPlot().getXValue(series, i), getPlot().getYValue(
87 series, i), getPlot().getXValue(series, i + 1), getPlot().getYValue(series, i + 1), new BasicStroke(
88 1.0f), Color.WHITE);
89 getPlot().getChart().getXYPlot().addAnnotation(annotation);
90 }
91 }
92 else if (event.getEntity() instanceof AxisEntity)
93 {
94 if (((AxisEntity) event.getEntity()).getAxis().equals(getPlot().getChart().getXYPlot().getDomainAxis()))
95 {
96 Quantity old = getPlot().getDomainQuantity();
97 getPlot().setDomainQuantity(getPlot().getOtherQuantity());
98 getPlot().setOtherQuantity(old);
99 getPlot().getChart().getXYPlot().getDomainAxis().setLabel(getPlot().getDomainQuantity().label());
100 getPlot().getChart().getXYPlot().zoomDomainAxes(0.0, null, null);
101 }
102 else
103 {
104 Quantity old = getPlot().getRangeQuantity();
105 getPlot().setRangeQuantity(getPlot().getOtherQuantity());
106 getPlot().setOtherQuantity(old);
107 getPlot().getChart().getXYPlot().getRangeAxis().setLabel(getPlot().getRangeQuantity().label());
108 getPlot().getChart().getXYPlot().zoomRangeAxes(0.0, null, null);
109 }
110 }
111 }
112
113
114 @SuppressWarnings("unchecked")
115 @Override
116 public void chartMouseMoved(final ChartMouseEvent event)
117 {
118 if (toggle != null)
119 {
120 toggle.chartMouseMoved(event);
121 }
122 boolean clearText = true;
123
124 if (event.getEntity() instanceof XYItemEntity)
125 {
126
127 XYItemEntity itemEntity = (XYItemEntity) event.getEntity();
128 int series = itemEntity.getSeriesIndex();
129 if (!getPlot().hasLineFD() || series != getPlot().getSeriesCount() - 1)
130 {
131 clearText = false;
132 int item = itemEntity.getItem();
133 double t = item * getPlot().getSource().getUpdateInterval().si;
134 getPlot().setTimeInfo(String.format(", %.0fs", t));
135 double x = getPlot().getXValue(series, item);
136 double y = getPlot().getYValue(series, item);
137 Range domain = getPlot().getChart().getXYPlot().getDomainAxis().getRange();
138 Range range = getPlot().getChart().getXYPlot().getRangeAxis().getRange();
139 TextAnchor anchor;
140 if (range.getUpperBound() - y < y - range.getLowerBound())
141 {
142
143 if (domain.getUpperBound() - x < x - domain.getLowerBound())
144 {
145
146 anchor = TextAnchor.TOP_RIGHT;
147 }
148 else
149 {
150
151 if ((range.getUpperBound() - y) / (range.getUpperBound() - range.getLowerBound()) < (x - domain
152 .getLowerBound()) / (domain.getUpperBound() - domain.getLowerBound()))
153 {
154
155 anchor = TextAnchor.TOP_RIGHT;
156 }
157 else
158 {
159
160 anchor = TextAnchor.BOTTOM_LEFT;
161 }
162 }
163 }
164 else if (domain.getUpperBound() - x < x - domain.getLowerBound())
165 {
166
167 anchor = TextAnchor.BOTTOM_RIGHT;
168 }
169 else
170 {
171
172 anchor = TextAnchor.BOTTOM_LEFT;
173 }
174 XYTextAnnotation textAnnotation = new XYTextAnnotation(String.format("%.0fs", t), x, y);
175 textAnnotation.setTextAnchor(anchor);
176 textAnnotation.setFont(textAnnotation.getFont().deriveFont(14.0f).deriveFont(Font.BOLD));
177 getPlot().getChart().getXYPlot().addAnnotation(textAnnotation);
178 }
179 }
180
181 if (clearText)
182 {
183 for (XYAnnotation annotation : ((List<XYAnnotation>) getPlot().getChart().getXYPlot().getAnnotations()))
184 {
185 if (annotation instanceof XYTextAnnotation)
186 {
187 getPlot().getChart().getXYPlot().removeAnnotation(annotation);
188 }
189 }
190 getPlot().setTimeInfo("");
191 }
192 }
193 };
194 }
195
196
197 @Override
198 protected void addPopUpMenuItems(final JPopupMenu popupMenu)
199 {
200 super.addPopUpMenuItems(popupMenu);
201 popupMenu.insert(new JPopupMenu.Separator(), 0);
202
203 JMenu updMenu = new JMenu("Update frequency");
204 ButtonGroup updGroup = new ButtonGroup();
205 for (int f : getPlot().getSource().getPossibleUpdateFrequencies())
206 {
207 String format = "%dx";
208 JRadioButtonMenuItem item = new JRadioButtonMenuItem(String.format(format, f));
209 item.setSelected(f == 1);
210 item.addActionListener(new ActionListener()
211 {
212
213 @Override
214 public void actionPerformed(final ActionEvent e)
215 {
216
217 if ((int) (.5 + getPlot().getSource().getAggregationPeriod().si / getPlot().getSource()
218 .getUpdateInterval().si) != f)
219 {
220 Duration interval = Duration.instantiateSI(getPlot().getSource().getAggregationPeriod().si / f);
221 for (FundamentalDiagram diagram : getPlot().getSource().getDiagrams())
222 {
223 diagram.setUpdateInterval(interval);
224 }
225
226
227 getPlot().getSource().setUpdateInterval(interval, getPlot().getUpdateTime().plus(interval.times(0.5)));
228
229 for (FundamentalDiagram diagram : getPlot().getSource().getDiagrams())
230 {
231 diagram.getChart().getXYPlot().zoomDomainAxes(0.0, null, null);
232 diagram.getChart().getXYPlot().zoomRangeAxes(0.0, null, null);
233 diagram.notifyPlotChange();
234 }
235 }
236 }
237 });
238 updGroup.add(item);
239 updMenu.add(item);
240 }
241 popupMenu.insert(updMenu, 0);
242
243 JMenu aggMenu = new JMenu("Aggregation period");
244 ButtonGroup aggGroup = new ButtonGroup();
245 for (double t : getPlot().getSource().getPossibleAggregationPeriods())
246 {
247 double t2 = t;
248 String format = "%.0f s";
249 if (t >= 60.0)
250 {
251 t2 = t / 60.0;
252 format = "%.0f min";
253 }
254 JRadioButtonMenuItem item = new JRadioButtonMenuItem(String.format(format, t2));
255 item.setSelected(t == getPlot().getSource().getAggregationPeriod().si);
256 item.addActionListener(new ActionListener()
257 {
258
259
260 @Override
261 public void actionPerformed(final ActionEvent e)
262 {
263 if (getPlot().getSource().getAggregationPeriod().si != t)
264 {
265 int n = (int) (0.5 + getPlot().getSource().getAggregationPeriod().si / getPlot().getSource()
266 .getUpdateInterval().si);
267 Duration period = Duration.instantiateSI(t);
268 Duration interval = period.divide(n);
269 for (FundamentalDiagram diagram : getPlot().getSource().getDiagrams())
270 {
271 diagram.setUpdateInterval(interval);
272 }
273
274 getPlot().getSource().setAggregationPeriod(period);
275 getPlot().getSource().setUpdateInterval(period.divide(n), getPlot().getUpdateTime().plus(period.divide(
276 n).times(0.5)));
277 for (FundamentalDiagram diagram : getPlot().getSource().getDiagrams())
278 {
279 diagram.getChart().getXYPlot().zoomDomainAxes(0.0, null, null);
280 diagram.getChart().getXYPlot().zoomRangeAxes(0.0, null, null);
281 diagram.notifyPlotChange();
282 }
283 }
284 }
285
286 });
287 aggGroup.add(item);
288 aggMenu.add(item);
289 }
290 popupMenu.insert(aggMenu, 0);
291 }
292
293
294
295
296
297 @Override
298 public FundamentalDiagram getPlot()
299 {
300 return (FundamentalDiagram) super.getPlot();
301 }
302
303 }