1. /**
  2.  * Just playing around a little with HTML 5 canvas
  3.  * and copying images between canvases.
  4.  *
  5.  * @author Chris Lercher
  6.  */
  7. public class PlayGwtHtml5CanvasMap implements EntryPoint {
  8.  
  9.   boolean drag = false;
  10.   int dragStartX;
  11.   int dragStartY;
  12.   int dragOffX;
  13.   int dragOffY;
  14.  
  15.   int currentX;
  16.   int currentY;
  17.  
  18.   @Override
  19.   public void onModuleLoad() {
  20.    
  21.     final Canvas hiddenCanvas = buildCanvas(1280, 1280);
  22.     drawHexPattern(hiddenCanvas);
  23.    
  24.     final Canvas visibleCanvas = buildCanvas(800, 600);
  25.    
  26.     showArea(hiddenCanvas, visibleCanvas, 0, 0);
  27.    
  28.    
  29.     // TODO Is there an easier way to track mouse dragging (avoiding the need for 4 handlers)?
  30.    
  31.     visibleCanvas.addMouseDownHandler(new MouseDownHandler() {
  32.      
  33.       @Override
  34.       public void onMouseDown(final MouseDownEvent event) {
  35.         drag = true;
  36.         dragStartX = event.getX();
  37.         dragStartY = event.getY();
  38.         dragOffX = 0;
  39.         dragOffY = 0;
  40.       }
  41.     });
  42.    
  43.     visibleCanvas.addMouseOutHandler(new MouseOutHandler() {
  44.      
  45.       @Override
  46.       public void onMouseOut(final MouseOutEvent event) {
  47.         drag = false;
  48.       }
  49.     });
  50.    
  51.     visibleCanvas.addMouseUpHandler(new MouseUpHandler() {
  52.      
  53.       @Override
  54.       public void onMouseUp(final MouseUpEvent event) {
  55.         drag = false;
  56.       }
  57.     });
  58.    
  59.     visibleCanvas.addMouseMoveHandler(new MouseMoveHandler() {
  60.      
  61.       @Override
  62.       public void onMouseMove(final MouseMoveEvent event) {
  63.         if (drag) {
  64.           final int oldDragOffX = dragOffX;
  65.           final int oldDragOffY = dragOffY;
  66.          
  67.           dragOffX = event.getX() - dragStartX;
  68.           dragOffY = event.getY() - dragStartY;
  69.          
  70.           currentX -= dragOffX - oldDragOffX;
  71.           currentY -= dragOffY - oldDragOffY;
  72.          
  73.           showArea(hiddenCanvas, visibleCanvas, currentX, currentY);
  74.         }
  75.       }
  76.     });
  77.    
  78.    
  79.     final RootPanel rootPanel = RootPanel.get();
  80.     rootPanel.add(new Label("Drag with the mouse to move the map (should work smoothly at least on " +
  81.             "current versions of Firefox and Chrome, not tested with other browsers)"));
  82.     rootPanel.add(visibleCanvas);
  83.   }
  84.  
  85.     private void showArea(final Canvas hiddenCanvas, final Canvas visibleCanvas, final double x, final double y) {
  86.       final Context2d hiddenCtx = hiddenCanvas.getContext2d();
  87.       final Context2d visibleCtx = visibleCanvas.getContext2d();
  88.       final ImageData imageData = hiddenCtx.getImageData(x, y, visibleCanvas.getCoordinateSpaceWidth(), visibleCanvas.getCoordinateSpaceHeight());
  89.       visibleCtx.putImageData(imageData, 0, 0);
  90.     }
  91.  
  92.   private Canvas buildCanvas(final int canvasWidth, final int canvasHeight) {
  93.     final Canvas canvas = Canvas.createIfSupported();
  94.    
  95.     canvas.setWidth(canvasWidth + "px");
  96.     canvas.setCoordinateSpaceWidth(canvasWidth);
  97.      
  98.     canvas.setHeight(canvasHeight + "px");      
  99.     canvas.setCoordinateSpaceHeight(canvasHeight);
  100.     return canvas;
  101.   }
  102.  
  103.   private static final String[] COLORS = new String[] {
  104.     "red", "green", "blue", "yellow", "maroon",
  105.      "fuchsia", "gold", "lawngreen",
  106.     "#303030", "#303030", "#303030", "#303030", "#303030"
  107.   };
  108.  
  109.   private void drawHexPattern(final Canvas canvas) {
  110.     final Context2d ctx = canvas.getContext2d();
  111.    
  112.     boolean rightShifted = false;
  113.     int xCount = 0;
  114.     int yCount = 0;
  115.    
  116.     final Random random = new Random();
  117.    
  118.     // TODO The offset deltas are hard-coded here, but should be variable depending on the hex size
  119.    
  120.     for (int yOff = 0; yOff < canvas.getCoordinateSpaceHeight(); yOff += 17) {
  121.       xCount = 0;
  122.       for (int xOff = 0; xOff < canvas.getCoordinateSpaceWidth(); xOff += 60) {
  123.        
  124.         ctx.save();
  125.         ctx.translate(xOff + (rightShifted ? 30 : 0), yOff);
  126.        
  127.         final String color =
  128. //            rightShifted ? COLORS[(xCount + yCount) % 7]
  129. //                         : COLORS[6 - ((xCount + yCount + 3) % 7)];
  130. //            
  131.             COLORS[random.nextInt(COLORS.length)];
  132.        
  133.         drawHex(ctx, 20., color);
  134.         ctx.restore();
  135.  
  136.         xCount ++;
  137.       }
  138.       rightShifted = !rightShifted;
  139.       yCount ++;
  140.     }
  141.   }
  142.  
  143.   private void drawHex(final Context2d ctx, final double scaleFactor, final String color) {
  144.    
  145.     ctx.save();
  146.     ctx.scale(scaleFactor, scaleFactor);
  147.     ctx.setLineWidth(1 / scaleFactor);
  148.    
  149.     ctx.beginPath();
  150.     final double alpha = 2. * Math.PI / 6.;
  151.     for (int i = 0; i < 6; i ++) {
  152.      
  153.       ctx.lineTo(1, 0);
  154.       ctx.rotate(alpha);
  155.     }
  156.     ctx.closePath();
  157.     ctx.stroke();
  158.     ctx.setFillStyle(color);
  159.     ctx.fill();
  160.    
  161.     ctx.restore();
  162.   }
  163.  
  164. }