Some comments and suggestions:
1 — Swing makes animated drawing pretty easy. I recommend you begin by drawing the image and drawing your graphic over it as shown below. This will often work just fine. If you must keep the drawing separate from the image rendering then I would suggest a non–opaque JPanel on top of the image component set in an OverlayLayout.
You can use a glass pane as shown in the tutorial but this covers the JRootPane which, if it includes other components may require
a – additional work to transfer InputEvents through to the components, and
b – translation of coordinates between glass pane and image component.
There is a third technique of doing all the rendering in a BufferedImage and simply painting the image in the 'paintComponent' method after each update in the animation. This works well for building up images/graphics over time.
2 – Using ImageIcon.getImage is an older method (j2se 1.2) for loading images. The single line of code does not give any feedback for loading problems although it is easy enough to add (ImageIcon and MediaTracker api). The newer way (j2se 1.4) is to use ImageIO whose 'read' methods return a BufferedImage. Using BufferedImages allow for software acceleration; your code can run faster.
Loading an image every time you render graphics (in 'paintComponent') is inefficient. You only need to load the image one time.
3 — it is common practice to use a javax.swing.Timer or a
thread for delays/animation. The example below shows one way of doing this.
4 — Canvas is an AWT component. You can mix AWT/heavyweight and Swing/lightweight components but it takes some care to get good results. It is generally recommended that we do not mix them. In Swing we generally use either JComponent or JPanel for custom drawing. JComponent is non–opaque by default and JPanel is opaque.
Here is a basic animation setup.
As far as zooming in and out of a portion of the graphics (image/drawings) you can use a Rectangle that can be resizable/draggable and expand the portion of the graphics it clips/contains to fill the graphic component. Or you can leave the Rectangle alone and scale the graphics it clips up or down. AffineTransform tries to make this easy with methods for scaling and translating. Also, the BufferedImage class has a handy 'subimage' method.