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().getSource().getNumberOfSeries() < 2 ? null
59 : GraphUtil.getToggleSeriesByLegendListener(getPlot().getLegend(), getPlot().getLaneVisible());
60 return new ChartMouseListener()
61 {
62
63 @SuppressWarnings({"unchecked", "synthetic-access"})
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),
87 getPlot().getYValue(series, i), getPlot().getXValue(series, i + 1),
88 getPlot().getYValue(series, i + 1), new BasicStroke(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({"synthetic-access", "unchecked"})
115 @Override
116 public void chartMouseMoved(final ChartMouseEvent event)
117 {
118 if (toggle != null)
119 {
120 toggle.chartMouseMoved(event);
121 }
122
123 if (event.getEntity() instanceof XYItemEntity)
124 {
125
126 XYItemEntity itemEntity = (XYItemEntity) event.getEntity();
127 int series = itemEntity.getSeriesIndex();
128 int item = itemEntity.getItem();
129 double t = item * getPlot().getSource().getUpdateInterval().si;
130 getPlot().setTimeInfo(String.format(", %.0fs", t));
131 double x = getPlot().getXValue(series, item);
132 double y = getPlot().getYValue(series, item);
133 Range domain = getPlot().getChart().getXYPlot().getDomainAxis().getRange();
134 Range range = getPlot().getChart().getXYPlot().getRangeAxis().getRange();
135 TextAnchor anchor;
136 if (range.getUpperBound() - y < y - range.getLowerBound())
137 {
138
139 if (domain.getUpperBound() - x < x - domain.getLowerBound())
140 {
141
142 anchor = TextAnchor.TOP_RIGHT;
143 }
144 else
145 {
146
147 if ((range.getUpperBound() - y)
148 / (range.getUpperBound() - range.getLowerBound()) < (x - domain.getLowerBound())
149 / (domain.getUpperBound() - domain.getLowerBound()))
150 {
151
152 anchor = TextAnchor.TOP_RIGHT;
153 }
154 else
155 {
156
157 anchor = TextAnchor.BOTTOM_LEFT;
158 }
159 }
160 }
161 else if (domain.getUpperBound() - x < x - domain.getLowerBound())
162 {
163
164 anchor = TextAnchor.BOTTOM_RIGHT;
165 }
166 else
167 {
168
169 anchor = TextAnchor.BOTTOM_LEFT;
170 }
171 XYTextAnnotation textAnnotation = new XYTextAnnotation(String.format("%.0fs", t), x, y);
172 textAnnotation.setTextAnchor(anchor);
173 textAnnotation.setFont(textAnnotation.getFont().deriveFont(14.0f).deriveFont(Font.BOLD));
174 getPlot().getChart().getXYPlot().addAnnotation(textAnnotation);
175 }
176
177 else
178 {
179 for (XYAnnotation annotation : ((List<XYAnnotation>) getPlot().getChart().getXYPlot().getAnnotations()))
180 {
181 if (annotation instanceof XYTextAnnotation)
182 {
183 getPlot().getChart().getXYPlot().removeAnnotation(annotation);
184 }
185 }
186 getPlot().setTimeInfo("");
187 }
188 }
189 };
190 }
191
192
193 @Override
194 protected void addPopUpMenuItems(final JPopupMenu popupMenu)
195 {
196 super.addPopUpMenuItems(popupMenu);
197 popupMenu.insert(new JPopupMenu.Separator(), 0);
198
199 JMenu updMenu = new JMenu("Update frequency");
200 ButtonGroup updGroup = new ButtonGroup();
201 for (int f : getPlot().getSource().getPossibleUpdateFrequencies())
202 {
203 String format = "%dx";
204 JRadioButtonMenuItem item = new JRadioButtonMenuItem(String.format(format, f));
205 item.setSelected(f == 1);
206 item.addActionListener(new ActionListener()
207 {
208
209 @Override
210 public void actionPerformed(final ActionEvent e)
211 {
212
213 if ((int) (.5 + getPlot().getSource().getAggregationPeriod().si
214 / getPlot().getSource().getUpdateInterval().si) != f)
215 {
216 Duration interval = Duration.instantiateSI(getPlot().getSource().getAggregationPeriod().si / f);
217 getPlot().setUpdateInterval(interval);
218
219
220 getPlot().getSource().setUpdateInterval(interval,
221 getPlot().getUpdateTime().plus(interval.times(0.5)), getPlot());
222 getPlot().getChart().getXYPlot().zoomDomainAxes(0.0, null, null);
223 getPlot().getChart().getXYPlot().zoomRangeAxes(0.0, null, null);
224 getPlot().notifyPlotChange();
225 }
226 }
227 });
228 updGroup.add(item);
229 updMenu.add(item);
230 }
231 popupMenu.insert(updMenu, 0);
232
233 JMenu aggMenu = new JMenu("Aggregation period");
234 ButtonGroup aggGroup = new ButtonGroup();
235 for (double t : getPlot().getSource().getPossibleAggregationPeriods())
236 {
237 double t2 = t;
238 String format = "%.0f s";
239 if (t >= 60.0)
240 {
241 t2 = t / 60.0;
242 format = "%.0f min";
243 }
244 JRadioButtonMenuItem item = new JRadioButtonMenuItem(String.format(format, t2));
245 item.setSelected(t == getPlot().getSource().getAggregationPeriod().si);
246 item.addActionListener(new ActionListener()
247 {
248
249
250 @SuppressWarnings("synthetic-access")
251 @Override
252 public void actionPerformed(final ActionEvent e)
253 {
254 if (getPlot().getSource().getAggregationPeriod().si != t)
255 {
256 int n = (int) (0.5 + getPlot().getSource().getAggregationPeriod().si
257 / getPlot().getSource().getUpdateInterval().si);
258 Duration period = Duration.instantiateSI(t);
259 getPlot().setUpdateInterval(period.divide(n));
260
261 getPlot().getSource().setAggregationPeriod(period);
262 getPlot().getSource().setUpdateInterval(period.divide(n),
263 getPlot().getUpdateTime().plus(period.divide(n).times(0.5)),
264 getPlot());
265 getPlot().getChart().getXYPlot().zoomDomainAxes(0.0, null, null);
266 getPlot().getChart().getXYPlot().zoomRangeAxes(0.0, null, null);
267 getPlot().notifyPlotChange();
268 }
269 }
270
271 });
272 aggGroup.add(item);
273 aggMenu.add(item);
274 }
275 popupMenu.insert(aggMenu, 0);
276 }
277
278
279
280
281
282 @Override
283 public FundamentalDiagram getPlot()
284 {
285 return (FundamentalDiagram) super.getPlot();
286 }
287
288 }