For information about the design and functionality of the MIDlet, see section Design.
The SvgCanvas2
class handles the setting up and
drawing of the pre-generated static SVG image. The constructor of
the class first sets up the 2D rendering context by using a ScalableGraphics
object:
public SvgCanvas2(boolean suppressKeyEvents) { super(suppressKeyEvents); // *** setup an instance of ScalableGraphics sg = ScalableGraphics.createInstance(); sg.setRenderingQuality(sg.RENDERING_QUALITY_HIGH);
Rendering quality is set to RENDERING_QUALITY_HIGH
, which is also the default setting on Series 40 and Nokia Asha software
platform devices. This quality level is dependent on the device and
the MIDlet code, and is mapped to definitions in the SVG specification
(shape, text, image, and color rendering). If you are concerned about
portability, check the specifications of the devices the MIDlet is
targeted for, since the results are different depending on device
capabilities.
The constructor then creates an SVGImage
using the content2.svg
file as a source, and sets the image dimensions to fit the device
screen using the SVGImage.setViewportWidth
and SVGImage.setViewportHeight
methods:
// *** load an svg image from a file try { InputStream svgStream = getClass().getResourceAsStream("content2.svg"); svgImage = (SVGImage) (SVGImage.createImage(svgStream, null)); // ** set the width and height of the document to match the screen capabilities svgImage.setViewportWidth(getWidth()); svgImage.setViewportHeight(getHeight()); } catch (Exception e) { e.printStackTrace(); } }
The GameCanvas.paint
method handles the painting
of the GameCanvas
. The ScalableGraphics
object renders the SVGImage
set up in the constructor:
public void paint(Graphics g) { // *** clear the display g.setColor(255, 255, 255); g.fillRect(0, 0, getWidth(), getHeight()); // *** render the SVG image sg.bindTarget(g); sg.setTransparency(1f); sg.render(0, 0, svgImage); sg.releaseTarget(); }
The ScalableGraphics.bindTarget
method sets where
the SVG image is rendered, that is, the target Graphics
object. Transparency is set to 1.0, which means fully opaque. The
image is drawn in the top-left corner of the GameCanvas
, at coordinates 0,0.
When the user selects Zoom In from the options menu, the following code is run:
public void zoomIn() { SVGSVGElement myEl = (SVGSVGElement) (svgImage.getDocument().getDocumentElement()); myEl.setCurrentScale(myEl.getCurrentScale() * 1.2f); repaint(); }
This modifies the scale property of the SVG document and redraws
the GameCanvas
, causing the SVG image to be displayed
larger. The other menu options for manipulating the image work similarly.
The following code, which is run when the user selects Restore View from the options menu, restores the original zoom and rotation settings:
public void restoreView() { SVGSVGElement myEl = (SVGSVGElement) svgImage.getDocument().getDocumentElement(); myEl.setCurrentRotate(0); myEl.setCurrentScale(1); SVGPoint origin = myEl.getCurrentTranslate(); origin.setX(0); origin.setY(0); repaint(); }
In the LoadStaticMidlet
class, map the Move and Zoom commands to action button 1:
/** * IconCommand is supported from Java Runtime 2.0.0 for Series 40 * onwards. Creates a new IconCommand Zoom with the given label, * unselected icon, selected icon, type and priority. */ cmZoom = new IconCommand("Zoom", zoomIcon, zoomIcon, IconCommand.ICON_OK, hotKey++); svgCanvas.addCommand(cmZoom); /** * IconCommand is supported from Java Runtime 2.0.0 for Series 40 * onwards. Creates a new IconCommand Move with the given label, * unselected icon, selected icon, type and priority. */ cmMove = new IconCommand("Move", moveIcon, moveIcon, IconCommand.ICON_OK, hotKey++); // ...
Implement gesture event handling in the SvgCanvas2
class. The initializeGesture
method sets up gesture event handling for the MIDlet. The gestureAction
method implements the actual event handling.
The MIDlet registers drag gestures, which it uses to move the image,
and pinch gestures, which it uses to zoom in and out of the image.
/** * Initializes gestures and set it to receive gesture events */ public void initializeGesture() { /** * Set the listener to register events for SvgCanvas2 (this,) and * register the GestureListener for the UI element (,this) */ GestureRegistrationManager.setListener(this, this); /** * Create an interactive zone and set it to receive taps */ GestureInteractiveZone myGestureZone = new GestureInteractiveZone(GestureInteractiveZone.GESTURE_PINCH | GestureInteractiveZone.GESTURE_DRAG); /** * Set the location (relative to the container) and size of the * interactive zone: */ myGestureZone.setRectangle(0, 0, getWidth(), getHeight()); /** * Register the interactive zone for GestureCanvas (this) */ GestureRegistrationManager.register(this, myGestureZone); } /** * Method to open the sensor connection. */ private SensorConnection openAccelerationSensor() { SensorInfo infos[] = SensorManager.findSensors("acceleration", null); if (infos.length == 0) { return null; } try { return (SensorConnection) Connector.open(infos[0].getUrl()); } catch (SecurityException se) { se.printStackTrace(); return null; } catch (IOException ioe) { ioe.printStackTrace(); System.out.println("Couldn't open sensor : " + infos[0].getUrl() + "!"); return null; } catch (IllegalArgumentException iae) { iae.printStackTrace(); return null; } } /** * Paint method. */ public void paint(Graphics g) { // *** clear the display g.setColor(255, 255, 255); g.fillRect(0, 0, getWidth(), getHeight()); // *** render the SVG image sg.bindTarget(g); sg.setTransparency(1f); //sg.render(0, 0, svgImage); sg.render((getWidth() - svgImage.getViewportWidth()) >> 1, (getHeight() - svgImage.getViewportHeight()) >> 1, svgImage); sg.releaseTarget(); } protected void sizeChanged(int w, int h) { svgImage.setViewportWidth(w); svgImage.setViewportHeight(h); repaint(); } /** * Restore the original view of the SVG Image. */ public void restoreView() { SVGSVGElement myEl = (SVGSVGElement) svgImage.getDocument().getDocumentElement(); myEl.setCurrentRotate(0); myEl.setCurrentScale(1); SVGPoint origin = myEl.getCurrentTranslate(); origin.setX(0); origin.setY(0); repaint(); } /** * Zoom in on the SVG Image. */ public void zoomIn() { SVGSVGElement myEl = (SVGSVGElement) (svgImage.getDocument().getDocumentElement()); myEl.setCurrentScale(myEl.getCurrentScale() * 1.2f); repaint(); } /** * Zoom out on the SVG Image. */ public void zoomOut() { SVGSVGElement myEl = (SVGSVGElement) (svgImage.getDocument().getDocumentElement()); myEl.setCurrentScale(myEl.getCurrentScale() * 0.8f); repaint(); } public void zoom(float zoom) { SVGSVGElement myEl = (SVGSVGElement) (svgImage.getDocument().getDocumentElement()); myEl.setCurrentScale(myEl.getCurrentScale() * zoom); repaint(); } /** * Rotate out on the SVG Image. */ public void rotateOut() { SVGSVGElement myEl = (SVGSVGElement) (svgImage.getDocument().getDocumentElement()); myEl.setCurrentRotate(myEl.getCurrentRotate() + 10); repaint(); } /** * Rotate in on the SVG Image. */ public void rotateIn() { SVGSVGElement myEl = (SVGSVGElement) (svgImage.getDocument().getDocumentElement()); myEl.setCurrentRotate(myEl.getCurrentRotate() - 10); repaint(); } public void pointerPressed(int x, int y) { } /** * Key repeat method. */ protected void keyRepeated(int keyCode) { keyPressed(keyCode); } /** * Handle key presses. */ protected void keyPressed(int keyCode) { SVGSVGElement svgDoc = (SVGSVGElement) svgImage.getDocument().getDocumentElement(); int action = getGameAction(keyCode); SVGPoint origin = svgDoc.getCurrentTranslate(); switch (action) { case RIGHT: origin.setX(origin.getX() + 5f); break; case LEFT: origin.setX(origin.getX() - 5f); break; case UP: origin.setY(origin.getY() - 5f); break; case DOWN: origin.setY(origin.getY() + 5f); break; } repaint(); } /* * Private members */ private ScalableGraphics sg; private SVGImage svgImage; /** * Defines the gestureAction method for the class. This method is called * every time a gesture event occurs for a UI element that uses * GestureListener. The method is called with all the information related to * the gesture event. */ public void gestureAction(Object arg0, GestureInteractiveZone arg1, GestureEvent gestureEvent) { switch (gestureEvent.getType()) { /** * Receives drag events and moves the image. */ case GestureInteractiveZone.GESTURE_DRAG: if (iconCommandState == IMAGE_MOVE) { SVGSVGElement svgDoc = (SVGSVGElement) svgImage.getDocument().getDocumentElement(); SVGPoint origin = svgDoc.getCurrentTranslate(); origin.setX(origin.getX() + gestureEvent.getDragDistanceX()); origin.setY(origin.getY() + gestureEvent.getDragDistanceY()); repaint(); } break; /** * This gesture event is supported from Java Runtime 2.0.0 for * Series 40 onwards. Receives pinch events and check the pinch * distance change to scale the current image. */ case GestureInteractiveZone.GESTURE_PINCH: if (iconCommandState == IMAGE_ZOOM) { int distanceChange = gestureEvent.getPinchDistanceChange(); if (distanceChange < 0) { zoomOut(); } else if (distanceChange > 0) { zoomIn(); } repaint(); } break; } }
In the SvgCanvas2
class, open a connection
to the accelerometer sensor, and implement the dataReceived
method for handling the returned sensor data. Use the sensor data
to determine the new x axis of the device (in case the user has rotated
the device) and rotate the image accordingly.
/** * Method to open the sensor connection. */ private SensorConnection openAccelerationSensor() { SensorInfo infos[] = SensorManager.findSensors("acceleration", null); if (infos.length == 0) { return null; } try { return (SensorConnection) Connector.open(infos[0].getUrl()); } catch (SecurityException se) { se.printStackTrace(); return null; } catch (IOException ioe) { ioe.printStackTrace(); System.out.println("Couldn't open sensor : " + infos[0].getUrl() + "!"); return null; } catch (IllegalArgumentException iae) { iae.printStackTrace(); return null; } } // ... /** * Notification of the received sensor data. */ public void dataReceived(SensorConnection arg0, Data[] arg1, boolean arg2) { // get sensor data for x int x = getX(arg1); // Rotate SVG Image with rotation if (x > 3) { rotateOut(); } else if (x < -3) { rotateIn(); } repaint(); } private int getX(Data[] aData) { int x_axis = 0; try { for (int i = 0; i < BUFFER_SIZE; i++) { x_axis += (int) aData[0].getDoubleValues()[0]; } x_axis = (int) (x_axis / BUFFER_SIZE); } catch (IllegalStateException e) { } return x_axis; } }