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 this.htmlGraphics2D = new HTMLGraphics2D();
128 this.extent = extent;
129 this.homeExtent = (Rectangle2D) extent.clone();
130 this.setBackground(Color.WHITE);
131 this.setPreferredSize(size);
132 this.size = (Dimension) size.clone();
133 this.lastDimension = this.getSize();
134 }
135
136
137
138
139
140 public String getDrawingCommands()
141 {
142 this.htmlGraphics2D.clearCommand();
143 this.paintComponent(this.htmlGraphics2D);
144 return this.htmlGraphics2D.closeAndGetCommands();
145 }
146
147
148
149
150
151 public void paintComponent(final HTMLGraphics2D g)
152 {
153 if (!this.getSize().equals(this.lastDimension))
154 {
155 this.lastDimension = this.getSize();
156 this.extent = Renderable2DInterface.Util.computeVisibleExtent(this.extent, this.getSize());
157 }
158 if (this.showGrid)
159 {
160 this.drawGrid(g);
161 }
162 }
163
164
165
166
167
168 public final synchronized void showGrid(final boolean bool)
169 {
170 this.showGrid = bool;
171 this.repaint();
172 }
173
174
175
176
177
178 public final Rectangle2D getExtent()
179 {
180 return this.extent;
181 }
182
183
184
185
186
187 public final synchronized void setWorldCoordinate(final Point2D point)
188 {
189 this.worldCoordinate = point;
190 }
191
192
193
194
195 public final synchronized Point2D getWorldCoordinate()
196 {
197 return this.worldCoordinate;
198 }
199
200
201
202
203 public final synchronized void displayWorldCoordinateToolTip()
204 {
205 if (this.showToolTip)
206 {
207 String worldPoint = "(x=" + this.formatter.format(this.worldCoordinate.getX()) + " ; y="
208 + this.formatter.format(this.worldCoordinate.getY()) + ")";
209 setToolTipText(worldPoint);
210 }
211 }
212
213
214
215
216 public final synchronized boolean isShowToolTip()
217 {
218 return this.showToolTip;
219 }
220
221
222
223
224 public final synchronized void setShowToolTip(final boolean showToolTip)
225 {
226 this.showToolTip = showToolTip;
227 }
228
229
230
231
232
233
234 public final synchronized void pan(final int direction, final double percentage)
235 {
236 if (percentage <= 0 || percentage > 1.0)
237 {
238 throw new IllegalArgumentException("percentage<=0 || >1.0");
239 }
240 switch (direction)
241 {
242 case LEFT:
243 this.extent.setRect(this.extent.getMinX() - percentage * this.extent.getWidth(), this.extent.getMinY(),
244 this.extent.getWidth(), this.extent.getHeight());
245 break;
246 case RIGHT:
247 this.extent.setRect(this.extent.getMinX() + percentage * this.extent.getWidth(), this.extent.getMinY(),
248 this.extent.getWidth(), this.extent.getHeight());
249 break;
250 case UP:
251 this.extent.setRect(this.extent.getMinX(), this.extent.getMinY() + percentage * this.extent.getHeight(),
252 this.extent.getWidth(), this.extent.getHeight());
253 break;
254 case DOWN:
255 this.extent.setRect(this.extent.getMinX(), this.extent.getMinY() - percentage * this.extent.getHeight(),
256 this.extent.getWidth(), this.extent.getHeight());
257 break;
258 default:
259 throw new IllegalArgumentException("direction unkown");
260 }
261 this.repaint();
262 }
263
264
265
266
267 public final synchronized void home()
268 {
269 this.extent = Renderable2DInterface.Util.computeVisibleExtent(this.homeExtent, this.getSize());
270 this.repaint();
271 }
272
273
274
275
276 public final boolean isShowGrid()
277 {
278 return this.showGrid;
279 }
280
281
282
283
284 public final void setShowGrid(final boolean showGrid)
285 {
286 this.showGrid = showGrid;
287 }
288
289
290
291
292
293 public final synchronized void zoom(final double factor)
294 {
295 zoom(factor, (int) (this.getWidth() / 2.0), (int) (this.getHeight() / 2.0));
296 }
297
298
299
300
301
302
303
304 public final synchronized void zoom(final double factor, final int mouseX, final int mouseY)
305 {
306 Point2D mwc =
307 Renderable2DInterface.Util.getWorldCoordinates(new Point2D.Double(mouseX, mouseY), this.extent, this.getSize());
308 double minX = mwc.getX() - (mwc.getX() - this.extent.getMinX()) * factor;
309 double minY = mwc.getY() - (mwc.getY() - this.extent.getMinY()) * factor;
310 double w = this.extent.getWidth() * factor;
311 double h = this.extent.getHeight() * factor;
312
313 this.extent.setRect(minX, minY, w, h);
314 this.repaint();
315 }
316
317
318
319
320
321
322 @SuppressWarnings("checkstyle:designforextension")
323 protected synchronized void drawGrid(final Graphics g)
324 {
325
326 g.setFont(g.getFont().deriveFont(11.0f));
327 g.setColor(GRIDCOLOR);
328 double scale = Renderable2DInterface.Util.getScale(this.extent, this.getSize());
329
330 int gridSizePixels = (int) Math.round(this.gridSize / scale);
331 if (gridSizePixels < 40)
332 {
333 this.gridSize = 10 * this.gridSize;
334 int maximumNumberOfDigits = (int) Math.max(0, 1 + Math.ceil(Math.log(1 / this.gridSize) / Math.log(10)));
335 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
336 this.drawGrid(g);
337 return;
338 }
339 if (gridSizePixels > 10 * 40)
340 {
341 int maximumNumberOfDigits = (int) Math.max(0, 2 + Math.ceil(Math.log(1 / this.gridSize) / Math.log(10)));
342 this.formatter.setMaximumFractionDigits(maximumNumberOfDigits);
343 this.gridSize = this.gridSize / 10;
344 this.drawGrid(g);
345 return;
346 }
347
348 double mod = this.extent.getMinX() % this.gridSize;
349 int x = (int) -Math.round(mod / scale);
350 while (x < this.getWidth())
351 {
352 Point2D point =
353 Renderable2DInterface.Util.getWorldCoordinates(new Point2D.Double(x, 0), this.extent, this.getSize());
354 if (point != null)
355 {
356 String label = this.formatter.format(Math.round(point.getX() / this.gridSize) * this.gridSize);
357 double labelWidth = this.getFontMetrics(this.getFont()).getStringBounds(label, g).getWidth();
358 if (x > labelWidth + 4)
359 {
360 g.drawLine(x, 15, x, this.getHeight());
361 g.drawString(label, (int) Math.round(x - 0.5 * labelWidth), 11);
362 }
363 }
364 x = x + gridSizePixels;
365 }
366
367 mod = Math.abs(this.extent.getMinY()) % this.gridSize;
368 int y = (int) Math.round(this.getSize().getHeight() - (mod / scale));
369 while (y > 15)
370 {
371 Point2D point =
372 Renderable2DInterface.Util.getWorldCoordinates(new Point2D.Double(0, y), this.extent, this.getSize());
373 if (point != null)
374 {
375 String label = this.formatter.format(Math.round(point.getY() / this.gridSize) * this.gridSize);
376 RectangularShape labelBounds = this.getFontMetrics(this.getFont()).getStringBounds(label, g);
377 g.drawLine((int) Math.round(labelBounds.getWidth() + 4), y, this.getWidth(), y);
378 g.drawString(label, 2, (int) Math.round(y + labelBounds.getHeight() * 0.3));
379 }
380 y = y - gridSizePixels;
381 }
382 }
383
384
385
386
387 public void repaint()
388 {
389
390 this.dirty = true;
391 }
392
393
394
395
396 public final Dimension getSize()
397 {
398 return this.size;
399 }
400
401
402
403
404 public final void setSize(Dimension size)
405 {
406 this.size = size;
407 }
408
409
410
411
412 public final Color getBackground()
413 {
414 return this.background;
415 }
416
417
418
419
420 public final void setBackground(Color background)
421 {
422 this.background = background;
423 }
424
425
426
427
428 public final int getWidth()
429 {
430 return this.size.width;
431 }
432
433
434
435
436 public final int getHeight()
437 {
438 return this.size.height;
439 }
440
441
442
443
444 public final Dimension getPreferredSize()
445 {
446 return this.preferredSize;
447 }
448
449
450
451
452 public final void setPreferredSize(Dimension preferredSize)
453 {
454 this.preferredSize = preferredSize;
455 }
456
457
458
459
460 public final String getToolTipText()
461 {
462 return this.toolTipText;
463 }
464
465
466
467
468 public final void setToolTipText(String toolTipText)
469 {
470 this.toolTipText = toolTipText;
471 }
472
473
474
475
476 public final boolean isShowing()
477 {
478 return this.showing;
479 }
480
481
482
483
484 public final void setShowing(boolean showing)
485 {
486 this.showing = showing;
487 }
488
489
490
491
492 public final Font getFont()
493 {
494 return this.currentFont;
495 }
496
497
498
499
500 public final void setFont(Font font)
501 {
502 this.currentFont = font;
503 }
504
505
506
507
508
509 public final FontMetrics getFontMetrics(Font font)
510 {
511 return this.canvas.getFontMetrics(font);
512 }
513
514
515
516
517 public final boolean isDirty()
518 {
519 return this.dirty;
520 }
521
522
523 @Override
524 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
525 {
526 return false;
527 }
528
529 }