2017년 3월 3일 금요일

Donut graphs using Canvas?


Does anyone have experience drawing a donut graph using canvas?

I am trying to plot a ratio in terms of a circle. For example. values of 1 and 3, would mean a donut with 4 sections of which 3 are shaded in blue and 1 in red.

This can probably be done using Google Charts API but want to enquire if it is possible using Canvas draw circle?

--
A donut graph is going to be difficult.   Impossible?    I do not think so however this will be a lot of work and will probably draw slowly.

Here are the tools Canvas has:

Methods

Clear()
Clears anything drawn on this Canvas but not any background color or image.
DrawCircle(number x, number y, number r)
Draws a circle (filled in) at the given coordinates on the canvas, with the given radius.
DrawLine(number x1, number y1, number x2, number y2)
Draws a line between the given coordinates on the canvas.
DrawPoint(number x, number y)
Draws a point at the given coordinates on the canvas.
DrawText(text text, number x, number y)
Draws the specified text relative to the specified coordinates using the values of the FontSize and TextAlignment properties.
DrawTextAtAngle(text text, number x, number y, number angle)
Draws the specified text starting at the specified coordinates at the specified angle using the values of the FontSize and TextAlignment properties.
number GetBackgroundPixelColor(number x, number y)
Gets the color of the specified point. This includes the background and any drawn points, lines, or circles but not sprites.
number GetPixelColor(number x, number y)
Gets the color of the specified point.
text Save()
Saves a picture of this Canvas to the device's external storage. If an error occurs, the Screen's ErrorOccurred event will be called.
text SaveAs(text fileName)
Saves a picture of this Canvas to the device's external storage in the file named fileName. fileName must end with one of .jpg, .jpeg, or .png, which determines the file type.
SetBackgroundPixelColor(number x, number y, number color)
Sets the color of the specified point. This differs from DrawPoint by having an argument for color.

You can draw a circle, but it is filled in.   So, you have to draw two circles, one larger than the other.


DrawCircle(number x, number y, number r)
Draws a circle (filled in) at the given coordinates on the canvas, with the given radius.

DrawCircle(250,250,  100)
DrawCircle(250,250, 50)

then you have to partition the circle(s) into four pieces.
Trig comes to the rescue.

You can use this to partition:


DrawLine(number x1, number y1, number x2, number y2)
Draws a line between the given coordinates on the canvas.
The first line is easy   DrawLine(250 - 50, 250, 250 - 100, 250)  perhaps  (because you will not draw the line from 250,250 but the circumffereance of the the smaller circle, so 250 +   or perhaps 250- on the x axis.

then you have to calculate where to draw the next three lines.   You will need to find a point on the circumference of both the smaller and larger circles  that represents the first 'pie slice'.   Here is where you will need a trig operation in you Math blocks.   Your next line is like your second; draw it a position of an arc representing the first piece slice plus the arc of the second perhaps.  Do it one more time.

Now you have to fill in all the pixels of each segment (actually truncated pie slices).

You have a single tool to fill in the slices:


SetBackgroundPixelColor(number x, number y, number color)
Sets the color of the specified point. This differs from DrawPoint by having an argument for color.
or perhaps use the DrawPoint and change the DrawPoint.Color

Now, you may have to calculate the position of every pixel within each segment ... possibly using a technique similar to drawing the segments themselves.

I do not think you want to do this, but if you do, or find a better way, please post the solution and your experience.


--
Here is a possible solution based on the ability for multiple rays to be drawn from the center of a circle to it's perimeter to fill each sector/wedge of a circle.
Two lists are passed to the procedure, one contains decimal values for the size of each slice of the pie and the other contains the color values for each slice.

I am trying to plot a ratio in terms of a circle. For example. values of 1 and 3, would mean a donut with 4 sections of which 3 are shaded in blue and 1 in red. 
For your example you would attach two lists of 4 items to the procedure:
0.25.0.25,0.25,0.25)
lightblue,blue,darkblue,red
But you could modify the procedure to take your values instead
--
Thanks Steve and Scott for your replies. It has given me some really good pointers (including the realization that I need to use trig functions).
Thanks again!

--
...and here is the Donut graph ecivon  if you have not already figured it out.  The key is Scott's Pie Chart ,  have fun.
Simple, when using Scott's Pie chart algorithm.... just add a white circle in the center of the pie chart.    

@Scott    Nice, 'easier' than I thought, you spent a lot of time figuring that out.  .... a post for Tips and Tricks?


--
Thanks, SteveJG  -- nice, simple solution :)
I would add that for larger charts the wedge colors may not fill completely so decreasing the 'by' value should fill better, but it will take longer to draw the chart.
(0.5 would likely take twice as long to draw)

--

App Inventor Developer Overview


Ellen Spertus (spertus@google.com)
José Dominguez (josmasflores@gmail.com)

1. Introduction

This document provides a high-level overview of the App Inventor source code, including the toolkits and libraries on which App Inventor depends, the different sub-projects within App Inventor, and information flow during the build process and execution.
There are differences between App Inventor and App Inventor 2, and these will be highlighted when appropriate.

2. Background

MIT App Inventor is a rather large system divided in multiple projects, each of which relies on different open source technologies. Before showing what each of those projects are (section 3), we introduce some of the technologies used within them.

2.1 Google Web Toolkit

Google Web Toolkit (GWT) allows programmers to write client-server applications in Java without worrying about the details of remote procedure calls (RPCs) except for providing explicit callbacks for RPCs (one for a successful call, one for failure).  GWT compiles the client code into JavaScript, which runs within a web browser, and the RPCs run as Java code on the server, with communication done via HTTP.  The reader is advised to learn about GWT before delving into the portion of App Inventor that runs in, or responds to requests from, the user’s browser.

2.2 Google App Engine

Google App Engine (GAE) is a cloud-computing platform that enables programs written in Java (or Python) to run and maintain data on Google servers.  The original internal version of App Inventor was built directly on proprietary Google infrastructure but, for the open source release, was rewritten to use GAE, using the third-party Objectify datastore API.
GWT and GAE play well together, where a GWT server can run on a GAE server.  This is how App Inventor works, as shown in Figure 1.
Figure 1: The App Inventor client and server are created with GWT, which converts the front-end code into JavaScript, which is run with the GWT client library in the user’s browser.  The back-end runs on the GWT server library as a Google App Engine service, using the third-party Objectify API for data storage.

2.3 Android

If you’ve never written an Android application before and if you’re going to work on components, the Hello, World tutorial is a good way to get started. If you are serious about writing components, you should also complete the Managing the Activity lifecycle section.

2.4 Scheme/Kawa

Kawa is a free implementation of Scheme that compiles to Java byte code, which can be converted by the tool dx into Dalvik bytecode.  We use Scheme as the internal representation of users’ programs, and part of the runtime library is written in Scheme.  These get compiled down to byte code and linked with our components library (written in Java) and external libraries (written in Java and C/C++) by the buildserver.

2.5 Blockly

In App Inventor 2, the blocks editor has been integrated into the browser, as opposed to the Java Web Start application that ships with App Inventor. Blockly is an open source library created by Googler Neil Fraser, and it’s written in JavaScript (using SVG).

3. App Inventor projects and directories

The App Inventor distribution consists of the following subdirectories, the first seven of which contain source code for sub-projects:
  • aiphoneapp: the interpreter that runs on the mobile device or emulator when it is connected to a computer running App Inventor.
  • aiplayapp: another version of the interpreter that runs on the mobile device or emulator when it is connected to a computer running App Inventor. This is what we call the MIT App Inventor Companion.
  • appengine: the GWT application that provides the Designer JavaScript code to the client browser and provides supporting server-side functionality, such as storing and retrieving projects and issuing compile requests to the buildserver.
  • blocklyeditor: the Blocks Editor, embedded in the browser and powered by Blockly. Used by both blockseditor and buildserver.
  • buildserver: an http server/servlet that takes a source zip file as input and produces an apk and/or error messages.
  • common: constants and utility classes used by other sub-projects.
  • components: code supporting App Inventor components, including annotations, implementations, and scripts for extracting component information needed by other sub-projects.  More information can be found in the documents:
The remaining two subdirectories contain static files:
  • docs: user-level documentation, such as tutorials.
  • lib: external libraries, such as JUnit, used by the various sub-projects.  They are listed below in External Libraries.
Figure 2-A shows where each of the projects’ code runs.  It is simplified in that it only shows the name of the project (e.g., blocklyeditor) and not specific build targets (e.g., BlocklyCompile).  Greater detail can be found in documents on each project (yet to be written) and in the Ant build.xml files in each project’s directory. Also note that the build server can be deployed in any cloud service, so any server accessible from the GAE server can be used (including locally in a development machine).
Figure 2-A: Components of the system and where they run.
External infrastructure components are black, parts of App Inventor red.
Figure 3 shows run-time communication among the different sub-projects.

3.1 Notes for App Inventor classic

The directory structure changes slightly in the classic version of App Inventor. Instead of a blocklyeditor project, the following two folders exist:
  • blockseditor: the Blocks Editor, which runs through JNLP on the client.
  • blockslib: library code (descended from the MIT Open Blocks library), used by both blockseditor and buildserver.
There is also a difference in the components figure. App Inventor classic is described as follows:
Figure 2-B shows where each of the projects’ code runs.  It is simplified in that it only shows the name of the project (e.g., blockslib) and not specific build targets (e.g., OpenBlocks).  Greater detail can be found in documents on each project (yet to be written) and in the Ant build.xml files in each project’s directory. Also note that although the diagrams depict Amazon EC2 as a potential platform to deploy part of the system, its use is not mandatory. Any server accessible from the GAE server can be used (including locally in a development machine).

Figure 2-B: Components of the system and where they run.
External infrastructure components are black, parts of App Inventor red.


4. Component Information Files

Several parts of the system need to know what components exist and their characteristics.  This information is generated at build time through a set of annotation processors that run over the components source code and generate files required in order to build the other App Inventor projects.  (Here, “project” refers to the parts of the App Inventor codebase, not user-created projects.)  These files can be found in the subdirectory appinventor/build/components.

4.1 simple_components.json

This file is used by the editor within the Designer in the GWT client (part of the appengine project).  Here are the keys, their meanings, and sample values for the AccelerometerSensor.
Key
Meaning
Sample value
name
the component’s name
AccelerometerSensor
version
a number incremented whenever the component’s API is changed (such as by adding a new Property)
1
categoryString
the section on the palette in which it should appear
SENSORS
helpString
descriptive HTML text shown when the user clicks the help icon to the right of the component’s name
“<p>Non-visible component that can detect shaking and measure acceleration...”
showOnPalette
whether to show the component on the palette (currently true for all components except for Form, which is automatically created)
true
nonVisible
false for GUI elements, true for non-GUI elements, such as sensors
true
iconName
a path to the component’s icon, relative to “appinventor/appengine/src/com/google/appinventor”
images/accelerometersensor.png
properties
a list containing the name, type, and default value of each property
[{ “name”: “Enabled”,
  “editorType”: “boolean”,
  “defaultValue”: “True”}]

4.2 simple_components.txt

This file, which simply lists component names alphabetically, one per line, is used by the buildserver when building user projects.

4.3 simple_components_permissions.json

This file, which is used by the buildserver to generate the permissions required by an app, has entries with the names and required permissions of each component, such as:
{"name": "Clock", "permissions": []},
{"name": "ContactPicker",
 "permissions": ["android.permission.INTERNET",
                "android.permission.READ_CONTACTS"]}

4.4 ya_lang_def.xml

This file contains the specification of the blocks used by blockseditor (via blockslib), including both static library functions and components with their methods, properties, and events.  Its header and footer come from the static files  OUTPUT_HEADER.txt and OUTPUT_FOOTER.txt in the src/com/google/appinventor/components/scripts/templates directory within the components project.  At the time of this writing, ya_lang_def was over 14,000 lines.  Here is a small excerpt:
<!-- TinyWebDB Component -->
<BlockGenus name="TinyWebDB" initlabel="TinyWebDB"
            label-unique="yes" editable-label="no" kind="command"
            is-starter="yes" is-terminator="yes" color="grey">
  <description>
    <text>Non-visible component that communicates with a Web service to store and retrieve information.</text>
  </description>
  <LangSpecProperties>
    <LangSpecProperty key="ya-kind" value="component"/>
    <LangSpecProperty key="component-version" value="2"/>
    <LangSpecProperty key="ya-event-1" value="TinyWebDB-GotValue"/>
    <LangSpecProperty key="ya-event-2" value="TinyWebDB-ValueStored"/>
    <LangSpecProperty key="ya-event-3" value="TinyWebDB-WebServiceError"/>
    <LangSpecProperty key="ya-prop-1" value="ServiceURL/read-write-property/text/"/>
    <LangSpecProperty key="ya-method-1" value="TinyWebDB-GetValue"/>
    <LangSpecProperty key="ya-type-method-1" value="Type-TinyWebDB-GetValue"/>
    <LangSpecProperty key="ya-method-2" value="TinyWebDB-StoreValue"/>
    <LangSpecProperty key="ya-type-method-2" value="Type-TinyWebDB-StoreValue"/>
  </LangSpecProperties>
</BlockGenus>

4.5 component-doc.html

This file, generated by the Ant target ComponentDocumentation (which does not appear as a dependency of any other target or task) contains reference documentation in HTML.  Descriptions are pulled from annotations or comments in the source code for components.  Here is an excerpt:
<h2 id="TinyDB">TinyDB</h2>
<p>Non-visible component that persistently stores values on the phone.</p>
<h3>Properties</h3>
none
<h3>Events</h3>
none
<h3>Methods</h3>
<dl>
  <dt><code>any GetValue(text tag)</code></dt>
  <dd>Retrieve the value stored under the given tag.</dd>
  <dt><code>StoreValue(text tag, any valueToStore)</code></dt>
  <dd>Store the given value under the given tag.  The storage
      persists on the phone when the app is restarted.</dd>
</dl>

5. External Libraries

A number of external libraries are included in the distribution under the subdirectory “appinventor/lib”.  Listed by directory, the are:
  • android: the Android SDK, used within the components project to generate:
  • animal_sniffer:  Animal Sniffer, used within the blockseditor project’s BlocksEditorTest to ensure that the Blocks Editor does not contain references to any methods added to the Java standard libraries after Java 5 (1.5).  (In the past, we had problems with String.isEmpty() sneaking in.) Note that this is for App Inventor classic only.
  • ant-contrib: Ant-Contrib, which defines the propertyregex task used within the macro ai.dojunit in build-common.xml.
  • appengine: the App Engine Java SDK required by the appengine project.
  • args4jArgs4j, a parser for command-line options used for the standalone version of the compiler (which is used to generate StarterApp) within the buildserver project.
  • blockly: this is the source code for the Blockly library in which the blocks editor in App Inventor 2 is based.
  • commons-fileupload: part of the Apache Commons, providing the ability to upload projects and individual asset files to the UploadServlet within the appengine project.
  • commons-io: part of the Apache Commons, providing the FileUtils class, which is used in BlockSaveFileTest.java in the blockslib project.
  • findbugsFindBugs, which is only included for its definition of javax.annotation.Nullable, which is required by the Guava GWT library.
  • gsonGson, a Java library to convert between JSON and Java objects, required by keyczar (below).
  • guavaGuava, a public version of some of the internal Google libraries on which the original version of App Inventor was written.
  • gwtGoogle Web Toolkit, used by appengine to create the browser client.
  • gwt_dragdropgwt-dnd, a drag-and-drop library for GWT.  This is used by appengine as part of the browser client.
  • gwt_incubator: the deprecated Google Web Toolkit Incubator.  The appengine project uses GWTCanvas and Color in the mock component implementation.
  • jdk5: this includes the API signature file (not library) jdk5.sig to be used by animal_sniffer (above) to ensure that the Blocks Editor does not contain references to any methods added to the Java standard libraries after Java 5 (1.5).   This was generated by a commented-out target, BuildJdk5Signature, in the build.xml file for blockseditor.
  • json: the reference Java library to parse JSON.  JSON is used throughout the system:
  • to encode the components used and their properties in a user project (Screen1.scm).
  • by the Form, GameClient, TinyDB, TinyWebDB, Voting, and Web components.
  • to encode the permissions associated with each component (simple_components_permissions.json, described above).

6. Programming Style

We generally follow these style guides:
An exception is that we use upper-camel-case (e.g., “MoveTo”) for component property, method, and event names.

7. Git Branches

The official App Inventor sources reside on GitHub in mit-cml/appinventor-sources.git The primary branches are:
  • master -- The current sources for MIT App Inventor 2
  • ai1 -- The last version of MIT App Inventor Classic
  • gh-pages -- This website (GitHub convention for “pages”)
  • ucr -- “Upcoming Component Release”
Periodically there will be other branches for a specified purpose, usually branches representing longer term development, often separately reviewed. Currently there is an “api4” branch where we are working on changes to support a minSdk of 4 (or greater).
There are two types of releases that we make on our public service. The more significant release we refer to as a “Component Release.” A Component release includes changes to components such that App Inventor programmers will need to update their version of the App Inventor Companion and we also need to update the buildservers (which package apps for people) to be able to use the new/modified component(s). Because projects are marked with the version of the components they were built with, once we perform a component release WE CANNOT GO BACK!!! It is also worth noting that Component releases require work on the part of App Inventor Programmers because they have to update the AI2 Companion on their devices and or within their copy of the Android Emulator. Because of the effort and testing required, we tend to avoid having too many component releases too close together. In general we have been doing a Component Release once per month.
By comparison “non component releases” are where we do not update components. For example changes to the App Inventor blocks layer, or other features of the Website itself. They can usually be backed out if there is a problem and they do require action on the part of App Inventor programmers.
Because we do not wish to do component releases too often, we do not always want to checking changes to the master branch which contain component changes. Instead we have a new branch named “ucr” where we will be merging component changes that pass review. When it comes time to do a Component Release, we will merge the ucr branch into the master branch prior to the release.

8. GitHub and Gerrit Reviews


Changes to MIT App Inventor should be made via the GitHub Workflow. In general we will not use GitHub to merge in changes. Instead after reviewing a change the release coordinators will squash your commits down to a single commit which will either be rebased on the master branch (non component change) or onto the ucr branch (component changes). Often as part of this work we will submit your commit to our private “Gerrit” review server which will arrange for automated running of our unit tests via the “Jenkins” continuous integration system. In general you do not need to be aware of this level of detail. Sometimes internal changes bypass the GitHub workflow and are reviewed directly on Gerrit, though this is happening less often now.