001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package com.sun.perseus.demo.locationBasedService;
033:
034: import java.util.Date;
035: import java.util.Vector;
036:
037: import javax.microedition.lcdui.*;
038: import javax.microedition.midlet.*;
039:
040: import org.w3c.dom.Document;
041: import org.w3c.dom.events.Event;
042: import org.w3c.dom.events.EventListener;
043: import org.w3c.dom.svg.SVGElement;
044: import org.w3c.dom.svg.SVGPoint;
045: import org.w3c.dom.svg.SVGRect;
046: import org.w3c.dom.svg.SVGSVGElement;
047: import org.w3c.dom.svg.SVGRGBColor;
048:
049: import com.sun.perseus.demo.PlaySVGImageDemo;
050:
051: /**
052: * An example of zooming and panning. A sample itinerary is used in combination
053: * with a map of downtown San Francisco to show how a route can be traced from a
054: * starting point to an ending point. This also demonstrates how to
055: * insert/remove the traced route into/from the map content so that the route
056: * can also be scaled with the map.
057: */
058: public final class LocationBasedService extends PlaySVGImageDemo
059: implements Runnable {
060: /**
061: * The image that holds the animated SVG content.
062: */
063: private static final String SVG_IMAGE = "/svg/locationBasedService.svg";
064:
065: /**
066: * The image that holds the splash screen image.
067: */
068: private static final String SPLASH_IMAGE = "/images/LocationBasedHelp.png";
069: Object[][] points = new Object[][] {
070: { new float[] { 14f, 60f }, "Washington and Battery" },
071: { new float[] { 14f, 146f }, "Left on Sacramento" },
072: { new float[] { 153f, 146f }, "Right on Drumm" },
073: { new float[] { 153f, 204f }, "Left on Market" },
074: { new float[] { 229f, 151f }, "Right on Stewart" },
075: { new float[] { 278f, 219f }, "First left" },
076: { new float[] { 312f, 194f }, "Left on Embarcadero" },
077: { new float[] { 275f, 141f }, "You made it!" } };
078:
079: /**
080: * Location markers
081: */
082: SVGElement[] markers = new SVGElement[points.length];
083:
084: /**
085: * Marker connectors
086: */
087: SVGElement[] connectors = new SVGElement[points.length - 1];
088:
089: /**
090: * Animation steps
091: */
092: Runnable initialDisplay = new InitialDisplay();
093: Runnable locationBasedServiceAnim = new LocationBasedServiceAnim();
094: Runnable finalDisplay = new FinalDisplay();
095:
096: /**
097: * Message element
098: */
099: SVGElement message;
100:
101: /**
102: * Message location
103: */
104: float messageX;
105:
106: /**
107: * Message location
108: */
109: float messageY;
110:
111: /**
112: * Message background
113: */
114: SVGElement messageBackground;
115:
116: /**
117: * Color constant for markers and connectors
118: */
119: // EXTENSION
120: // final String MARKER_COLOR = "red";
121: // REPLACE WITH
122: SVGRGBColor MARKER_COLOR = null;
123: SVGRGBColor MARKER_BLACK = null;
124: SVGRGBColor MARKER_WHITE = null;
125:
126: /**
127: * Current Animation
128: */
129: Runnable step = initialDisplay;
130:
131: /**
132: * Initial viewbox
133: */
134: SVGRect initialVB;
135:
136: /**
137: * Initial screen bbox
138: */
139: SVGRect initialBBox;
140:
141: /**
142: * Controls whether the animation is paused or not
143: */
144: boolean paused = true;
145:
146: /**
147: * Default constructor
148: */
149: public LocationBasedService() {
150: super (SVG_IMAGE, SPLASH_IMAGE, false);
151: }
152:
153: /**
154: * By default, start the demo in the playing state.
155: */
156: public void startApp() {
157: super .startApp();
158:
159: init(svgImage.getDocument());
160: }
161:
162: /**
163: * @param doc the DocumentNode holding the expected SVG content.
164: */
165: public void init(final Document doc) {
166: svg = (SVGSVGElement) doc.getDocumentElement();
167: // EXTENSION
168: MARKER_COLOR = svg.createSVGRGBColor(255, 0, 0);
169: MARKER_BLACK = svg.createSVGRGBColor(0, 0, 0);
170: MARKER_WHITE = svg.createSVGRGBColor(255, 255, 255);
171:
172: final SVGElement inserts = (SVGElement) doc
173: .getElementById("inserts");
174:
175: //
176: // Add markers for each of the locationBasedService points
177: //
178: final SVGElement markersGroup = (SVGElement) doc
179: .createElementNS(SVG_NAMESPACE_URI, "g");
180:
181: markersGroup.setTrait("visibility", "visible");
182:
183: for (int i = 0; i < points.length; i++) {
184: Object[] point = points[i];
185: float[] coord = (float[]) point[0];
186: SVGElement marker = (SVGElement) doc.createElementNS(
187: SVG_NAMESPACE_URI, "ellipse");
188: marker.setFloatTrait("cx", coord[0]);
189: marker.setFloatTrait("cy", coord[1]);
190: marker.setFloatTrait("rx", 5);
191: marker.setFloatTrait("ry", 5);
192: // EXTENSION
193: // marker.setTrait("fill", MARKER_COLOR);
194: // REPLACE WITH
195: marker.setRGBColorTrait("fill", MARKER_COLOR);
196: markersGroup.appendChild(marker);
197: markers[i] = marker;
198: }
199:
200: //
201: // Add connector lines for each of the locationBasedService points
202: // except the last.
203: //
204: final SVGElement connectorsGroup = (SVGElement) doc
205: .createElementNS(SVG_NAMESPACE_URI, "g");
206: connectorsGroup.setTrait("fill", "none");
207: // EXTENSION
208: // connectorsGroup.setTrait("stroke", MARKER_COLOR);
209: // REPLACE WITH
210: connectorsGroup.setRGBColorTrait("stroke", MARKER_COLOR);
211: connectorsGroup.setFloatTrait("stroke-width", 2.5f);
212:
213: for (int i = 0; i < (points.length - 1); i++) {
214: connectors[i] = (SVGElement) doc.createElementNS(
215: SVG_NAMESPACE_URI, "line");
216: connectors[i].setTrait("visibility", "hidden");
217: connectors[i].setFloatTrait("x1", markers[i]
218: .getFloatTrait("cx"));
219: connectors[i].setFloatTrait("y1", markers[i]
220: .getFloatTrait("cy"));
221: connectors[i].setFloatTrait("x2", markers[i]
222: .getFloatTrait("cx"));
223: connectors[i].setFloatTrait("y2", markers[i]
224: .getFloatTrait("cy"));
225: connectorsGroup.appendChild(connectors[i]);
226: }
227:
228: //
229: // Message
230: //
231: message = (SVGElement) doc.createElementNS(SVG_NAMESPACE_URI,
232: "text");
233: message.setTrait("text-anchor", "middle");
234: // EXTENSION
235: // message.setTrait("fill", "black");
236: // REPLACE WITH
237: message.setRGBColorTrait("fill", MARKER_BLACK);
238: // EXTENSION
239: // message.setTrait("fill-opacity", "0.5");
240: // message.setTrait("font-family", "SunSansDemiEmbeded");
241: messageBackground = (SVGElement) doc.createElementNS(
242: SVG_NAMESPACE_URI, "rect");
243: // EXTENSION
244: // messageBackground.setTrait("fill", "white");
245: // REPLACE WITH
246: messageBackground.setRGBColorTrait("fill", MARKER_WHITE);
247: // EXTENSION
248: // messageBackground.setFloatTrait("fill-opacity", 0.75f);
249:
250: //
251: // Remember the initial viewbox & screenBBox
252: //
253: initialVB = svg.getRectTrait("viewBox");
254: initialBBox = svg.getScreenBBox();
255:
256: inserts.appendChild(connectorsGroup);
257: inserts.appendChild(markersGroup);
258: svg.appendChild(messageBackground);
259: svg.appendChild(message);
260:
261: Thread th = new Thread() {
262: public void run() {
263: while (true) {
264: try {
265: if (state == STATE_PLAYING) {
266: if (!paused) {
267: svgAnimator
268: .invokeAndWait(LocationBasedService.this );
269: }
270: }
271:
272: sleep(200);
273: } catch (InterruptedException ie) {
274: break;
275: }
276: }
277: }
278: };
279:
280: th.start();
281: }
282:
283: public void keyPressed(int keyCode) {
284: if (keyCode == KEY_START_DEMO) {
285: if (state != STATE_PLAYING) {
286: svgAnimator.play();
287: state = STATE_PLAYING;
288: }
289:
290: paused = !paused;
291: } else if (keyCode == KEY_ROTATE) {
292: if (state == STATE_PLAYING) {
293: svgAnimator.invokeLater(new Runnable() {
294: public void run() {
295: if (svg == null) {
296: System.err.println("svg is null!!!!");
297: }
298:
299: if (svg.getCurrentRotate() == 0) {
300: // Rotate by 90 degrees counter clock wise
301: svg.setCurrentRotate(-90);
302:
303: // Scale by the height / width factor
304: float scale = svgCanvas.getHeight()
305: / initialBBox.getWidth();
306: svg.setCurrentScale(scale);
307:
308: // Move the origin to bthe bottom left of the display.
309: SVGPoint pan = svg.getCurrentTranslate();
310: pan.setX(-initialBBox.getY() * scale);
311: pan.setY(svgCanvas.getHeight());
312: } else {
313: svg.setCurrentRotate(0);
314:
315: SVGPoint pan = svg.getCurrentTranslate();
316: pan.setX(0);
317: pan.setY(0);
318: svg.setCurrentScale(1);
319: }
320: }
321: });
322: }
323: } else if (keyCode == KEY_HELP) {
324: if (splashCanvas != null) {
325: // If the demo is playing, pause it
326: final boolean wasPaused = paused;
327:
328: if (state == STATE_PLAYING) {
329: paused = true;
330: }
331:
332: // Show the splashCanvas for a little while.
333: Display.getDisplay(this ).setCurrent(splashCanvas);
334:
335: Thread th = new Thread() {
336: public void run() {
337: System.err.println("Starting to sleep");
338:
339: try {
340: Thread.currentThread().sleep(
341: SPLASH_MIN_LENGTH);
342: } catch (InterruptedException ie) {
343: }
344:
345: System.err.println("done sleeping");
346: Display.getDisplay(LocationBasedService.this )
347: .setCurrent(svgCanvas);
348:
349: if (!wasPaused) {
350: paused = false;
351: }
352: }
353: };
354:
355: th.start();
356: }
357: }
358: }
359:
360: public void run() {
361: step.run();
362: }
363:
364: class InitialDisplay implements Runnable {
365: long start = 0;
366: long pauseFor = 3000;
367: long animSteps = 5;
368: long curAnimStep = 0;
369:
370: public void run() {
371: if (start == 0) {
372: start = System.currentTimeMillis();
373:
374: // Hide markers and connectors
375: for (int i = 0; i < markers.length; i++) {
376: markers[i].setTrait("visibility", "hidden");
377: }
378:
379: // Position initial message
380: messageX = initialVB.getX()
381: + (initialVB.getWidth() / 2);
382: messageY = initialVB.getY()
383: + (initialVB.getHeight() / 2);
384: message.setFloatTrait("x", messageX);
385: message.setFloatTrait("y", messageY);
386: message.setTrait("#text", "Your Itinerary");
387:
388: float fontSize = 40;
389: message.setFloatTrait("font-size", fontSize);
390:
391: messageBackground.setFloatTrait("x",
392: initialVB.getX() + 20);
393: messageBackground
394: .setFloatTrait("y",
395: (initialVB.getY() + (initialVB
396: .getHeight() / 2))
397: - fontSize);
398: messageBackground.setFloatTrait("width", initialVB
399: .getWidth() - 40);
400: messageBackground.setFloatTrait("height",
401: (3 * fontSize) / 2);
402: message.setTrait("visibility", "visible");
403: messageBackground.setTrait("visibility", "visible");
404: curAnimStep = 0;
405: } else {
406: // Animate the viewbox to the first locationBasedService point
407: long curTime = System.currentTimeMillis();
408: long aLength = curTime - start;
409: float messageFontSize = 6;
410:
411: if (aLength > pauseFor) {
412: message.setTrait("visibility", "hidden");
413: messageBackground.setTrait("visibility", "hidden");
414:
415: if (curAnimStep >= animSteps) {
416: LocationBasedService.this .step = locationBasedServiceAnim;
417: start = 0;
418: message.setFloatTrait("font-size",
419: messageFontSize);
420: } else {
421: float p = (curAnimStep + 1) / (float) animSteps;
422: SVGRect vb = svg.getRectTrait("viewBox");
423: float[] coord = (float[]) points[0][0];
424: vb.setX(coord[0] - 40);
425: vb.setY(coord[1] - 40);
426: vb.setWidth(80);
427: vb.setHeight((vb.getWidth() * initialVB
428: .getHeight())
429: / initialVB.getWidth());
430:
431: vb.setX(initialVB.getX()
432: + (p * (vb.getX() - initialVB.getX())));
433: vb.setY(initialVB.getY()
434: + (p * (vb.getY() - initialVB.getY())));
435: vb.setWidth(initialVB.getWidth()
436: + (p * (vb.getWidth() - initialVB
437: .getWidth())));
438: vb.setHeight(initialVB.getHeight()
439: + (p * (vb.getHeight() - initialVB
440: .getHeight())));
441:
442: svg.setRectTrait("viewBox", vb);
443: curAnimStep++;
444: }
445: }
446: }
447: }
448: }
449:
450: class LocationBasedServiceAnim implements Runnable {
451: int cur = 0;
452: long start = 0;
453: long pauseFor = 1500;
454: long animateFor = 2000;
455: int curAnimStep = 0;
456: int animSteps = 5;
457: float messageFontSize = 6;
458:
459: public void run() {
460: if (cur == LocationBasedService.this .points.length) {
461: cur = 0;
462: LocationBasedService.this .step = finalDisplay;
463: } else {
464: if (start == 0) {
465: // Show the new marker
466: markers[cur].setTrait("visibility", "visible");
467:
468: // Show the connector line to the next marker
469: // if there is a next marker, i.e except the last
470: // marker.
471: if (cur < connectors.length) {
472: connectors[cur].setTrait("visibility",
473: "visible");
474: connectors[cur].setFloatTrait("x2",
475: connectors[cur].getFloatTrait("x1"));
476: connectors[cur].setFloatTrait("y2",
477: connectors[cur].getFloatTrait("y1"));
478: }
479:
480: // Set the viewbox to be around the new
481: // point of interest
482: SVGRect vb = svg.getRectTrait("viewBox");
483: float[] coord = (float[]) points[cur][0];
484: vb.setX(coord[0] - 40);
485: vb.setY(coord[1] - 40);
486: vb.setWidth(80);
487: vb
488: .setHeight((vb.getWidth() * initialVB
489: .getHeight())
490: / initialVB.getWidth());
491: svg.setRectTrait("viewBox", vb);
492:
493: // Show message
494: messageX = vb.getX() + (vb.getWidth() / 2);
495: messageY = (vb.getY() + vb.getHeight()) - 2;
496: message.setFloatTrait("x", messageX);
497: message.setFloatTrait("y", messageY);
498: message.setTrait("#text", (String) points[cur][1]);
499: messageBackground.setFloatTrait("x", vb.getX());
500: messageBackground.setFloatTrait("y", messageY
501: - messageFontSize);
502: messageBackground.setFloatTrait("width", 80);
503: messageBackground.setFloatTrait("height",
504: (4 * messageFontSize) / 3);
505: messageBackground.setTrait("visibility", "visible");
506: message.setTrait("visibility", "visible");
507:
508: // Starting now
509: start = System.currentTimeMillis();
510:
511: curAnimStep = 0;
512: } else {
513: long curTime = System.currentTimeMillis();
514: long aLength = curTime - start;
515:
516: if (aLength > pauseFor) {
517: messageBackground.setTrait("visibility",
518: "hidden");
519: message.setTrait("visibility", "hidden");
520:
521: if ((cur == (LocationBasedService.this .points.length - 1))
522: || ((aLength > pauseFor) && (curAnimStep >= animSteps))) {
523: cur++;
524: start = 0;
525: curAnimStep = 0;
526: messageBackground.setTrait("visibility",
527: "hidden");
528: message.setTrait("visibility", "hidden");
529: } else {
530: SVGRect vb = svg.getRectTrait("viewBox");
531: float[] startCoord = (float[]) points[cur][0];
532: float[] endCoord = (float[]) points[cur + 1][0];
533: float p = (curAnimStep + 1)
534: / (float) animSteps;
535: float x = startCoord[0]
536: + (p * (endCoord[0] - startCoord[0]));
537: float y = startCoord[1]
538: + (p * (endCoord[1] - startCoord[1]));
539: vb.setX(x - 40);
540: vb.setY(y - 40);
541: vb.setWidth(80);
542: vb.setHeight((vb.getWidth() * initialVB
543: .getHeight())
544: / initialVB.getWidth());
545: connectors[cur].setFloatTrait("x2", x);
546: connectors[cur].setFloatTrait("y2", y);
547: svg.setRectTrait("viewBox", vb);
548: curAnimStep++;
549: }
550: }
551: }
552: }
553: }
554: }
555:
556: class FinalDisplay implements Runnable {
557: long start = 0;
558: SVGRect startVB;
559: long animateFor = 2000;
560: long pauseFor = 3000;
561: boolean vpRestored = false;
562:
563: public void run() {
564: if (start == 0) {
565: startVB = svg.getRectTrait("viewBox");
566: message.setTrait("#text",
567: ((String) points[points.length - 1][1]));
568: start = System.currentTimeMillis();
569: vpRestored = false;
570: } else {
571: long curTime = System.currentTimeMillis();
572:
573: if ((curTime - start) < animateFor) {
574: float p = (curTime - start) / (float) animateFor;
575: SVGRect vb = svg.getRectTrait("viewBox");
576: vb
577: .setX(startVB.getX()
578: + (p * (initialVB.getX() - startVB
579: .getX())));
580: vb
581: .setY(startVB.getY()
582: + (p * (initialVB.getY() - startVB
583: .getY())));
584: vb.setWidth(startVB.getWidth()
585: + (p * (initialVB.getWidth() - startVB
586: .getWidth())));
587: vb.setHeight(startVB.getHeight()
588: + (p * (initialVB.getHeight() - startVB
589: .getHeight())));
590: svg.setRectTrait("viewBox", vb);
591: } else if (!vpRestored) {
592: svg.setRectTrait("viewBox", initialVB);
593: vpRestored = true;
594: } else if ((curTime - start) > (animateFor + pauseFor)) {
595: start = 0;
596: step = initialDisplay;
597: paused = true;
598:
599: for (int ci = 0; ci < connectors.length; ci++) {
600: connectors[ci].setTrait("visibility", "hidden");
601: }
602:
603: for (int mi = 0; mi < markers.length; mi++) {
604: markers[mi].setTrait("visibility", "hidden");
605: }
606: }
607: }
608: }
609: }
610: }
|