1 package nl.tudelft.simulation.dsol.web.animation.D2;
2
3 import java.awt.Canvas;
4 import java.awt.Color;
5 import java.awt.Dimension;
6 import java.awt.Font;
7 import java.awt.FontMetrics;
8 import java.awt.Graphics;
9 import java.awt.Image;
10 import java.awt.geom.Point2D;
11 import java.awt.geom.Rectangle2D;
12 import java.awt.geom.RectangularShape;
13 import java.awt.image.ImageObserver;
14 import java.text.NumberFormat;
15
16 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
17 import nl.tudelft.simulation.dsol.web.animation.HTMLGraphics2D;
18
19
20
21
22
23
24
25
26
27
28
29
30 public class HTMLGridPanel implements ImageObserver
31 {
32
33 public static final int UP = 1;
34
35
36 public static final int DOWN = 2;
37
38
39 public static final int LEFT = 3;
40
41
42 public static final int RIGHT = 4;
43
44
45 public static final double ZOOMFACTOR = 1.2;
46
47
48 protected static final Color GRIDCOLOR = Color.BLACK;
49
50
51 @SuppressWarnings("checkstyle:visibilitymodifier")
52 protected Rectangle2D extent = null;
53
54
55 @SuppressWarnings("checkstyle:visibilitymodifier")
56 protected Rectangle2D homeExtent = null;
57
58
59 @SuppressWarnings("checkstyle:visibilitymodifier")
60 protected boolean showGrid = true;
61
62
63 @SuppressWarnings("checkstyle:visibilitymodifier")
64 protected double gridSize = 100.0;
65
66
67 @SuppressWarnings("checkstyle:visibilitymodifier")
68 protected NumberFormat formatter = NumberFormat.getInstance();
69
70
71 @SuppressWarnings("checkstyle:visibilitymodifier")
72 protected Dimension lastDimension = null;
73
74
75 @SuppressWarnings("checkstyle:visibilitymodifier")
76 protected Dimension size = null;
77
78
79 @SuppressWarnings("checkstyle:visibilitymodifier")
80 protected Dimension preferredSize = null;
81
82
83 @SuppressWarnings("checkstyle:visibilitymodifier")
84 protected Point2D worldCoordinate = new Point2D.Double();
85
86
87 @SuppressWarnings("checkstyle:visibilitymodifier")
88 protected boolean showToolTip = true;
89
90
91 private Color background;
92
93
94 private String toolTipText = "";
95
96
97 private boolean showing = true;
98
99
100 private Font currentFont = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
101
102
103 private Canvas canvas = new Canvas();
104
105
106 protected HTMLGraphics2D htmlGraphics2D;
107
108
109 private boolean dirty = false;
110
111
112
113
114
115 public HTMLGridPanel(final Rectangle2D extent)
116 {
117 this(extent, new Dimension(600, 600));
118 }
119
120
121
122
123
124
125 public HTMLGridPanel(final Rectangle2D extent, final Dimension size)
126 {
127 super();
128 this.htmlGraphics2D = new HTMLGraphics2D();
129 this.extent = extent;
130 this.homeExtent = (Rectangle2D) extent.clone();
131 this.setBackground(Color.WHITE);
132 this.setPreferredSize(size);
133 this.size = (Dimension) size.clone();
134 this.lastDimension = this.getSize();
135 }
136
137
138
139
140
141 public String getDrawingCommands()
142 {
143 this.htmlGraphics2D.clearCommand();
144 this.paintComponent(this.htmlGraphics2D);
145 return this.htmlGraphics2D.closeAndGetCommands();
146 }
147
148
149
150
151
152 public void paintComponent(final HTMLGraphics2D g)
153 {
154 if (!this.getSize().equals(this.lastDimension))
155 {
156 this.lastDimension = this.getSize();
157 this.extent = Renderable2DInterface.Util.computeVisibleExtent(this.extent, this.getSize());
158 }
159 if (this.showGrid)
160 {
161 this.drawGrid(g);
162 }
163 }
164
165
166
167
168
169 public final synchronized void showGrid(final boolean bool)
170 {
171 this.showGrid = bool;
172 this.repaint();
173 }
174
175
176
177
178
179 public final Rectangle2D getExtent()
180 {
181 return this.extent;
182 }
183
184
185
186
187
188 public final synchronized void setWorldCoordinate(final Point2D point)
189 {
190 this.worldCoordinate = point;
191 }
192
193
194
195
196 public final synchronized Point2D getWorldCoordinate()
197 {
198 return this.worldCoordinate;
199 }
200
201
202
203
204 public final synchronized void displayWorldCoordinateToolTip()
205 {
206 if (this.showToolTip)
207 {
208 String worldPoint = "(x=" + this.formatter.format(this.worldCoordinate.getX()) + " ; y="
209 + this.formatter.format(this.worldCoordinate.getY()) + ")";
210 setToolTipText(worldPoint);
211 }
212 }
213
214
215
216
217 public final synchronized boolean isShowToolTip()
218 {
219 return this.showToolTip;
220 }
221
222
223
224
225 public final synchronized void setShowToolTip(final boolean showToolTip)
226 {
227 this.showToolTip = showToolTip;
228 }
229
230
231
232
233
234
235 public final synchronized void pan(final int direction, final double percentage)
236 {
237 if (percentage <= 0 || percentage > 1.0)
238 {
239 throw new IllegalArgumentException("percentage<=0 || >1.0");
240 }
241 switch (direction)
242 {
243 case LEFT:
244 this.extent.setRect(this.extent.getMinX() - percentage * this.extent.getWidth(), this.extent.getMinY(),
245 this.extent.getWidth(), this.extent.getHeight());
246 break;
247 case RIGHT:
248 this.extent.setRect(this.extent.getMinX() + percentage * this.extent.getWidth(), this.extent.getMinY(),
249 this.extent.getWidth(), this.extent.getHeight());
250 break;
251 case UP:
252 this.extent.setRect(this.extent.getMinX(), this.extent.getMinY() + percentage * this.extent.getHeight(),
253 this.extent.getWidth(), this.extent.getHeight());
254 break;
255 case DOWN:
256 this.extent.setRect(this.extent.getMinX(), this.extent.getMinY() - percentage * this.extent.getHeight(),
257 this.extent.getWidth(), this.extent.getHeight());
258 break;
259 default:
260 throw new IllegalArgumentException("direction unkown");
261 }
262 this.repaint();
263 }
264
265
266
267
268 public final synchronized void home()
269 {
270 this.extent = Renderable2DInterface.Util.computeVisibleExtent(this.homeExtent, this.getSize());
271 this.repaint();
272 }
273
274
275
276
277 public final boolean isShowGrid()
278 {
279 return this.showGrid;
280 }
281
282
283
284
285 public final void setShowGrid(final boolean showGrid)
286 {
287 this.showGrid = showGrid;
288 }
289
290
291
292
293
294 public final synchronized void zoom(final double factor)
295 {
296 zoom(factor, (int) (this.getWidth() / 2.0), (int) (this.getHeight() / 2.0));
297 }
298
299
300
301
302
303
304
305 public final synchronized void zoom(final double factor, final int mouseX, final int mouseY)
306 {
307 Point2D mwc =
308 Renderable2DInterface.Util.getWorldCoordinates(new Point2D.Double(mouseX, mouseY), this.extent, this.getSize());
309 double minX = mwc.getX() - (mwc.getX() - this.extent.getMinX()) * factor;
310 double minY = mwc.getY() - (mwc.getY() - this.extent.getMinY()) * factor;
311 double w = this.extent.getWidth() * factor;
312 double h = this.extent.getHeight() * factor;
313
314 this.extent.setRect(minX, minY, w, h);
315 this.repaint();
316 }
317
318
319
320
321
322
323 @SuppressWarnings("checkstyle:designforextension")
324 protected synchronized void drawGrid(final Graphics g)
325 {
326
327 g.setFont(g.getFont().deriveFont(11.0f));
328 g.setColor(GRIDCOLOR);
329 double scale = Renderable2DInterface.Util.getScale(this.extent, this.getSize());
330
331 int gridSizePixels = (int) Math.round(this.gridSize / scale);
332 if (gridSizePixels < 40)
333 {
334 this.gridSize = 10 * this.gridSize;
335 int maximumNumberOfDigits = (int) Math.max(0, 1 + Math.ceil(Math.log(1 / this.gridSize) / Math.log(10)));
336 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
337 this.drawGrid(g);
338 return;
339 }
340 if (gridSizePixels > 10 * 40)
341 {
342 int maximumNumberOfDigits = (int) Math.max(0, 2 + Math.ceil(Math.log(1 / this.gridSize) / Math.log(10)));
343 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
344 this.gridSize = this.gridSize / 10;
345 this.drawGrid(g);
346 return;
347 }
348
349 double mod = this.extent.getMinX() % this.gridSize;
350 int x = (int) -Math.round(mod / scale);
351 while (x < this.getWidth())
352 {
353 Point2D point =
354 Renderable2DInterface.Util.getWorldCoordinates(new Point2D.Double(x, 0), this.extent, this.getSize());
355 if (point != null)
356 {
357 String label = this.formatter.format(Math.round(point.getX() / this.gridSize) * this.gridSize);
358 double labelWidth = this.getFontMetrics(this.getFont()).getStringBounds(label, g).getWidth();
359 if (x > labelWidth + 4)
360 {
361 g.drawLine(x, 15, x, this.getHeight());
362 g.drawString(label, (int) Math.round(x - 0.5 * labelWidth), 11);
363 }
364 }
365 x = x + gridSizePixels;
366 }
367
368 mod = Math.abs(this.extent.getMinY()) % this.gridSize;
369 int y = (int) Math.round(this.getSize().getHeight() - (mod / scale));
370 while (y > 15)
371 {
372 Point2D point =
373 Renderable2DInterface.Util.getWorldCoordinates(new Point2D.Double(0, y), this.extent, this.getSize());
374 if (point != null)
375 {
376 String label = this.formatter.format(Math.round(point.getY() / this.gridSize) * this.gridSize);
377 RectangularShape labelBounds = this.getFontMetrics(this.getFont()).getStringBounds(label, g);
378 g.drawLine((int) Math.round(labelBounds.getWidth() + 4), y, this.getWidth(), y);
379 g.drawString(label, 2, (int) Math.round(y + labelBounds.getHeight() * 0.3));
380 }
381 y = y - gridSizePixels;
382 }
383 }
384
385
386
387
388 public void repaint()
389 {
390
391 this.dirty = true;
392 }
393
394
395
396
397 public final Dimension getSize()
398 {
399 return this.size;
400 }
401
402
403
404
405 public final void setSize(Dimension size)
406 {
407 this.size = size;
408 }
409
410
411
412
413 public final Color getBackground()
414 {
415 return this.background;
416 }
417
418
419
420
421 public final void setBackground(Color background)
422 {
423 this.background = background;
424 }
425
426
427
428
429 public final int getWidth()
430 {
431 return this.size.width;
432 }
433
434
435
436
437 public final int getHeight()
438 {
439 return this.size.height;
440 }
441
442
443
444
445 public final Dimension getPreferredSize()
446 {
447 return this.preferredSize;
448 }
449
450
451
452
453 public final void setPreferredSize(Dimension preferredSize)
454 {
455 this.preferredSize = preferredSize;
456 }
457
458
459
460
461 public final String getToolTipText()
462 {
463 return this.toolTipText;
464 }
465
466
467
468
469 public final void setToolTipText(String toolTipText)
470 {
471 this.toolTipText = toolTipText;
472 }
473
474
475
476
477 public final boolean isShowing()
478 {
479 return this.showing;
480 }
481
482
483
484
485 public final void setShowing(boolean showing)
486 {
487 this.showing = showing;
488 }
489
490
491
492
493 public final Font getFont()
494 {
495 return this.currentFont;
496 }
497
498
499
500
501 public final void setFont(Font font)
502 {
503 this.currentFont = font;
504 }
505
506
507
508
509
510 public final FontMetrics getFontMetrics(Font font)
511 {
512 return this.canvas.getFontMetrics(font);
513 }
514
515
516
517
518 public final boolean isDirty()
519 {
520 return this.dirty;
521 }
522
523
524 @Override
525 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
526 {
527 return false;
528 }
529
530 }