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 }