Creating Dart-based graphics





This blog post shows you how to create a Dart file that renders Canvas-based graphics (just for fun), followed by instructions for creating an Android application that renders the same graphics.

The contents of the Java class, the HTML page, and the Dart file are not discussed, but most of the content is straightforward. If need be, you can perform a Google search to find links that provide additional explanatory information.

Another point to keep in mind is that the Dart-based graphics is rendered in an 800x500 region, which is rendered appropriately in a laptop browser. If you want to render graphics that conform to the dimensions of a smart phone, you need to make some tweaks to the Dart code.

For your convenience, there is an Android apk for this blog post and the complete Eclipse-based Android project that you can download from this link:
http://code.google.com/p/dart-graphics

Part 1: Getting the Google Dart code
You need the Google Dart code in order to perform step #3 in this blog post. Open a command shell, navigate to your $HOME directory, and then download the Dart project from the command line as follows:
svn checkout http://dart.googlecode.com/svn/trunk/ dart-read-only

The preceding command creates a copy of the Google Dart code in $HOME/dart-read-only.

Before proceeding to step #2, you may need to perform some additional steps (depending on your platform) as described here:
http://code.google.com/p/dart/wiki/PreparingYourMachine

After your machine is ready, create a sample directory $HOME/dart-read-only/dart/mysample, which is a convenient location when you perform step #3 below.


Part 2: Creating the three Dart-related files
1) Create a Dart file ArchTripleCirclesTube2.dart
2) Create ArchTripleCirclesTube2.html which references the Dart file
3) Generate the file ArchTripleCirclesTube2-js.html

Step 1:
Create the directory $DART_HOME/mysample and then put the Google Dart file ArchTripleCirclesTube2.dart in Listing 1 in this newly created directory.

Step 2:
Put the HTML page ArchTripleCirclesTube2.html in Listing 2 in the same directory as step #1.

Step 3:
Generate the HTML page ArchTripleCirclesTube2-js.html (in the same directory as step #1) by first navigating to your mysample directory and then launching the following command from the command line:
python ../dart/client/tools/htmlconverter.py ArchTripleCirclesTube2.html -o .

The preceding command generates the HTML page ArchTripleCirclesTube2-js.html in the current directory. This generated HTML page is an eight megabyte file, so you can view its contents in an editor on your own machine. Now launch this HTML page in a browser and view the graphics display.

Part 3: Creating/deploying an Android application
You need to perform the following steps:
4) create an Android project (version >= 7)
5) create a subdirectory 'www' under $PROJECT_ROOT/assets
6) copy the generated HTML file into the 'www' subdirectory
7) modify the generated Android Activity class
8) modify the XML file $PROJECT_ROOT/res/layout/main.xml
9) launch an emulator or attach a device

Step 4:
Create a standard Android project in Eclipse (creation details are omitted). The project name in this example is ArchTripleCirclesTube2, and the package name is com.iquarkt.android.

Step 5:
Create the subdirectory www under $PROJECT_ROOT/assets.

Step 6:
Copy ArchTripleCirclesTube2-js.html (from step #3) into $PROJECT_ROOT/assets/www.

Step 7:
Replace the contents of $PROJECT_ROOT/src/com/iquarkt/android/ArchTripleCirclesTube2Activity.java with the Java code in Listing 3.

Step 8:
Replace the contents of the $PROJECT_ROOT/res/layout/main.xml with the following contents:
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>

Step 9:
Launch an Android emulator, or attach a smart phone through a USB port on your laptop, and in Eclipse deploy your Android application.


Listing 1: ArchTripleCirclesTube2.dart

 

Code:
#library('ArchTripleCirclesTube2');
#import('dart:dom');

main() {
  new ArchTripleCirclesTube2();
}

class ArchTripleCirclesTube2 {
   CanvasRenderingContext2D context;

   var maxWidth     = 800;
   var maxHeight    = 500;
   var basePointX   = 280;
   var basePointY   = 240;
   var currentX     = 0;
   var currentY     = 0;
   var offsetX      = 0;
   var offsetY      = 0;
   var radius       = 0;
   var circleRadius = 80;
   var lineWidth    = 1;
   var Constant     = 0.25;
   var angle        = 0;
   var deltaAngle   = 1;
   var maxAngle     = 720;
   var index        = 720;
   var factor       = 1;

   static final stripWidth = 45;
   static final factorValues = const [1.0, 0.5];


   ArchTripleCirclesTube2() {
     var doc = window.document;
     HTMLCanvasElement canvas = doc.getElementById("canvas");
     context = canvas.getContext("2d");

     drawGraphics();
   }

   void drawGraphics() {
     context.clearRect(0, 0, maxWidth, maxHeight);

     for(angle=0; angle<maxAngle; angle+=deltaAngle) {
        // compute circle coordinates
        radius   = Constant*angle;
        offsetX  = radius*Math.cos(angle*Math.PI/180);
        offsetY  = radius*Math.sin(angle*Math.PI/180);
        currentX = basePointX+offsetX;
        currentY = basePointY-offsetY;

        index = ((angle/stripWidth)).floor();
        factor = factorValues[index%2];

        // draw first circle
        context.beginPath();
        context.lineWidth = lineWidth;

        if(angle/deltaAngle % 2 == 0) {
           context.setFillColor("red");
        } else {
           context.setFillColor("blue");
        }

        context.arc(currentX, currentY, factor*circleRadius,
                    0, Math.PI*2, true);

        context.fill();
        context.closePath();
        context.stroke();

        // draw second circle
        context.beginPath();
        context.lineWidth = lineWidth;

        if(angle/deltaAngle % 2 == 0) {
           context.setFillColor("red");
        } else {
           context.setFillColor("yellow");
        }

        context.arc(currentX+circleRadius, currentY,
                    factor*circleRadius, 0, Math.PI*2, true);

        context.fill();
        context.closePath();
        context.stroke();

        // draw third circle
        context.beginPath();
        context.lineWidth = lineWidth;

        if(angle/deltaAngle % 2 == 0) {
           context.setFillColor("yellow");
        } else {
           context.setFillColor("blue");
        }

        context.arc(currentX+circleRadius/2, currentY-circleRadius/2,
                    factor*circleRadius, 0, Math.PI*2, true);

        context.fill();
        context.closePath();
        context.stroke();
     }
   }
}

 

 


Listing 2: ArchTripleCirclesTube2.html

 

 

Code:
<html>
  <head>
    <title>Archimedean Triple Circles</title>
  </head>

  <body>
    <div class="image"></div>
    <div id="main">
      <canvas id="canvas" width="800" height="500"></canvas>
    </div>
    <script type="application/dart" src="ArchTripleCirclesTube2.dart"></script>
  </body>
</html>

 


Listing 3: ArchTripleCirclesTube2.java

 

 

 

Code:
package com.iquarkt.android;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class ArchTripleCirclesTube2 extends Activity
{
   WebView mWebView;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.setWebViewClient(new TravelClient());
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setDomStorageEnabled(true);
        mWebView.loadUrl("file:///android_asset/www/ArchTripleCirclesTube2-js.html");
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private class TravelClient extends WebViewClient {
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
           System.out.println("URL: " + url);
           view.loadUrl("javascript:changeLocation('" + url + "')");
           return true;
        }
    }
}

 


Part 4: Additional Dart-related resources
These links contain more information about Dart and additional download links:
* http://code.google.com/p/dart/
* http://www.dartlang.org/