VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 73 –
CHAPTER 7
BASIC GRAPHICS, EVENTS,
AND GLOBAL DATA
In this chapter, the graphics features of TouchDevelop are introduced and then combined with
scripts when an action, such as turning the phone around, is performed. That topic leads very natu-
rally to scripts which access the sensors built into a Windows phone. Providing code to be executed
whenever an event is triggered then leads naturally into scripts which use global data items.
7.1 GRAPHICS FACILITIES
7.2 EVENTS AND SENSORS
7.3 GLOBAL DATA
7.1 GRAPHICS FACILITIES
The phone’s screen is composed of many dots which can be illuminated in different colors. All
characters, all lines, all pictures seen on the screen are displayed as patterns of these dots where
the phone’s software has selected the color and intensity for each dot.
Graphics programming is, in effect, a matter of writing code to set the color and intensity of each
dot in an area of the screen. Anyone who has had some previous experience with graphics pro-
gramming can skip the following brief introduction to the subject. After that introduction, we will
move on to the facilities for graphics programming provided in TouchDevelop.
COMPUTER GRAPHICS TERMINOLOGY
Each dot on the screen is known as a PICTURE ELEMENT and that term is usually abbreviated to
PIXEL or to PEL. We will use the term pixel. The TouchDevelop API for setting the pixel’s color and
intensity uses a triple of three numbers. In most graphics software, these three numbers are
one-byte integers in the range 0 to 255, and they specify the intensity of the red, green and blue
components of the color separately. However TouchDevelop scales these numbers to be in the
range 0.0 to 1.0.
The triple of three numbers is commonly called an RGB VALUE. An integer value of 0 means that the
color component has zero intensity and a value of 1.0 means maximum intensity. Some typical
combinations of integers as RGB values in TouchDevelop are:
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 74 –
(0.0, 0.0, 0.0) black (0.0, 1.0, 0.0) green
(1.0, 1.0, 1.0) white (0.0, 0.0, 1.0) blue
(0.5, 0.5, 0.5) gray (1.0, 1.0, 0.0) yellow
(1.0, 0,0, 0.0) red (1.0, 0.0, 1.0) purple
The pixels on the screen are arranged in a rectangular grid. Each pixel has a coordinate position in
this grid given by an x value and a y value. The x values start at 0 and increase
from left-to-right across the screen; the y values start at 0 and increase from top
to bottom down the screen. (Note that y-axis values grow in the opposite direc-
tion to how you would normally draw a graph.)
The size of the displayable area on the screen is exactly 480 pixels wide by 800
pixels high for a Windows 7 phone. This means that the x and y coordinates can
range from (0,0) in the top-left corner to (479,799) in the bottom right corner,
as shown on the right.
A TRIVIAL GRAPHICS PROGRAM
A short graphics program was used as an example in Chapter 2.
It begins by creating a new Picture value and assigning it to variable pic. It is an array of pixel values
480 wide and 300 wide. The width is the maximum which can be displayed on a Windows phone.
The height of 300 is much less than the maximum 800 allowed for the phone. The pixels are initial-
ized to be white. The second statement draws a solid rectangle in the Picture array. The top left
corner of the rectangle is at (10,10) – i.e. 10 pixels in from the left and 10 pixels down from the top.
The width of the rectangle is 200 pixels and its height is 100 pixels. The fifth argument of 0 means
that we do not want to rotate the rectangle before drawing it onto the picture object. (To be more
precise, it is rotated by 0 degrees.) The last parameter specified the color to use for the rectangle.
The colors→red value is equivalent to using (1.0,0.0,0.0) as the RGB value for the pixels, and is
much more readable.
Figure 7.1: Trivial graphics script
VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 75 –
The third statement draws a solid ellipse inside the Picture array. One has to imagine that the el-
lipse fits inside a rectangle whose top left corner is at the coordinates (270,190). The width and
height of that ellipse are set to be 200 and 100 respectively. Again, we rotate that containing rec-
tangle by 0 degrees. The color for the ellipse is chosen to be blue.
The fourth statement draws the four sides of a rectangle at approximately the extreme edges of the
Picture array. The thickness of the lines used for the four sides has been set at 3 pixels. The color of
the lines is whatever has been chosen in the phone’s settings as the accent color; for the screen shot
shown below, that accent color is magenta.
The fifth statement draws a line from the bottom left corner up towards the top right corner, and
the thickness of the line is chosen to be 3 pixels wide.
Finally the last statement sends the picture to be displayed on the wall. A screen shot of our pro-
gram’s output appears in Figure 7.2.
MORE DETAILS ABOUT PICTURES
Any photograph held on the phone or downloadable from the web is held as a Picture value too.
This means that you can write scripts which transform the photograph or overwrite them in some
way. Anything is possible given enough effort spent developing a script.
Just to introduce you to the possibilities, Figure 7.3 shows a script which first prompts the user to
enter a string (to use as the value of the parameter msg), then asks the user to select a photograph
from amongst those on the phone, overprints a text message diagonally across the picture from the
bottom left to the top right and finally displays the picture.
Figure 7.2: Output from trivial graphics script
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 76 –
The script has to make some calculations to determine a suitable size for the characters in the mes-
sage being displayed and what angle to draw the text at, if we want that text to be along the diago-
nal. The character size calculation is very approximate (as not all characters are the same width)
and the formula used here was found by trial and error.
The angle of the diagonal is found by computing the arctangent of height/width for the image. The
math function atan2 provided in the TouchDevelop API performs that calculation but returns the
result in radians. The angle argument to the draw text method requires the angle in degrees how-
ever, so a call to the rad to deg conversion function is needed too. Finally a minus sign is needed in
front because we are drawing the text in a direction which ascends from left to right which corre-
sponds to an anticlockwise rotation, whereas the draw text method normally performs a clockwise
rotation on the text. A sample output from this script is shown in Figure 7.4.
Note that the photograph selected for display in Figure 7.4 is too large to fit on the screen. Its width
is 800 pixels yet the screen itself is only 480 pixels wide. The post to wall method scaled the image
by a factor of 480/800 in both dimensions so that it would fit without having to scroll the image
from side to side.
Figure 7.3: Script to Overprint a Photograph
VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 77 –
Table 7.1 provides a description of most of the methods available for the Picture datatype.
Table 7.1: Useful Picture Methods
Method Description
Operations on the Image as a Whole
height: Number Returns the picture height in pixels
width: Number Returns the picture width in pixels
invert: Picture Inverts the R,G,B color components of every pixel
clear(col:Color): Nothing Sets all pixels to color col
clone: Picture Returns a duplicate of the picture
post to wall: Nothing Displays the picture on the screen, resizing it if necessary
to fit within the maximum width of 480 pixels and a
maximum height of 800 pixels.
crop(x:Number, y:Number, w:Number,
h:Number): Nothing
Crops the picture to have width w and height h, selecting
a subimage whose top left corner is at position x,y
blend(other:Picture, x:Number,
y:Number, angle:Number,
alpha:Number): Nothing
Overwrites this picture with picture, other, putting its top
left corner at position x,y and rotating about that corner
by angle degrees in a clockwise direction; alpha is used
as the transparency of all pixels in the other picture.
resize(w:Number, h:Number): Nothing Scales the picture to have width w and height h
Figure 7.4: Output from the Overprint Photograph Script
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 78 –
Shape Drawing Methods
draw ellipse(x:Number, y:Number,
w:Number, h:Number, angle:Number,
c:Color, th:Number): Nothing
Draws the largest ellipse which fits inside a rectangle
with width w and height h; the top left corner of the rec-
tangle is at position x,y; the rectangle is rotated about the
top left corner by angle degrees in a clockwise direction;
the line has a thickness of th pixels and is drawn in color
c.
draw line(x1:Number, y1:Number,
x2:Number, y2:Number, c:Color,
th:Number): Nothing
Draws a line from position x1,y1 to position x2,y2; the
line has thickness of th pixels and is drawn in color c.
draw rect(x:Number, y:Number,
w:Number, h:Number, angle:Number,
c:Color, th:Number): Nothing
Draws a rectangle whose top left corner is at position x,y;
it has width w and height h; the rectangle is rotated about
the top left corner by angle degrees in a clockwise direc-
tion; the line has a thickness of th pixels and is drawn in
color c.
draw text(x:Number, y:Number,
txt:String, fs:Number,
angle:Number, c:Color): Nothing
Draws text as pixels in color c on the picture; the top left
of the first character is at position x,y; the size used for
the characters is fs; the text is rotated by angle degrees
about the x,y position.
fill ellipse(x:Number, y:Number,
w:Number, h:Number, angle:Number,
c:Color): Number
Like draw ellipse except that the ellipse is drawn as a
solid object (not as a line surrounding an elliptically
shaped area)
fill rect(x:Number, y:Number,
w:Number, h:Number, angle:Number,
c:Color): Nothing
Like draw rect except that the rectangle is drawn as a
solid object (not as four lines surrounding a rectangular
area)
Access to Pixels
pixel(x:Number, y:Number): Color Returns the color of the pixel at position x,y
set pixel(x:Number, y:Number,
c:Color): Nothing
Sets the pixel at position x,y to have color c
WORKING WITH PIXELS
As explained earlier, each pixel has a color and an intensity determined by a triple of three num-
bers, the RGB values. There is an additional number attached to each pixel which comes into play if
we want to superimpose one picture on top of another. This additional integer is known as the AL-
PHA value and controls the degree of transparency of the pixel.
Suppose that we want to overlay part of picture A with picture B. Should the pixels from Picture B
replace the pixels of A? This is usually known as knockout overprinting. It means that you cannot
see through the pixels from picture B and see any remnants of picture A in the overlaid area. How-
ever, perhaps the colors of the B picture pixels should be blended with the pixels of the A picture so
VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 79 –
that you can see both the A and B images combined? The alpha values associated with the B pixels
determine their degrees of transparency. If alpha is 1.0, the pixel is fully opaque and the B pixel will
knockout (replace) the A pixel. If alpha is 0.0, the pixel is fully transparent and no trace of picture B
will be seen when overlaid on picture A. Intermediate values for alpha result in partial transparen-
cy for the B picture.
Given a picture referenced by variable pic, the pixel at coordinates x,y can be retrieved by a state-
ment like the following.
var col := pic→pixel(x,y)
The value so obtained has the datatype Color. That value can be decomposed into its A (alpha), R, G
and B components with statements like these:
var red component := col→R
var green component := col→G
var blue component := col→B
var alpha component := col→A
We can change these color components in any way we like, as long as the values stay in the 0.0 to
1.0 range, and then recombine them to create a new color which can be stored back into the picture
as a changed pixel value. For example, the following code inverts the color intensities, giving an ef-
fect similar to creating a color negative image:
red component := 1.0 - red component
green component := 1.0 - green component
blue component := 1.0 - blue component
col := colors→from argb(alpha component, red component, green component, blue component)
pic→set pixel(x, y, col)
However that particular sequence of statements would rarely be needed because the Picture
datatype has an invert method which performs exactly that operation to every pixel in the image.
Many of the methods used for working with colors and individual pixels are listed below in Table
7.2. They are accessed from the service named colors. For example,
var y := colors→yellow
declares variable y to have the type Color and initializes it to the yellow color.
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 80 –
Table 7.2: Methods provided by the colors Service
Method Description
Composing and Decomposing Color Values
from argb(alpha:Number, r:Number,
g:Number, b:Number): Color
Constructs a color from the alpha and RGB values, which
must all be in the range 0.0 to 1.0
from rgb(r:Number, g:Number,
b:Number): Color
Constructs a color from the RGB values provided; the al-
pha component is set to 1.0 (totally opaque)
Access to the Phone’s Theme Colors
accent: Color
background: Color
foreground: Color
chrome: Color
subtle: Color
Returns the accent, background, foreground, chrome and
subtle (light gray) colors selected for the phone’s theme
in its Settings menu
Standard Colors
black: Color
blue: Color
brown: Color
cyan: Color
dark gray: Color
gray: Color
green: Color
light gray: Color
magenta: Color
orange: Color
purple: Color
red: Color
white: Color
yellow: Color
Obtain standard colors by their usual names.
Obtaining Special Colors
random: Color Returns a random (opaque) color
linear gradient(c1:Color, c2:Color,
alpha:Number): Color
Computes a color in between c1 and c2 where c2 over-
lays c1 with the specified alpha factor for transparency.
7.2 EVENTS AND SENSORS
The Windows phone contains a number of sensors, such as an accelerometer, which can trigger
events that get passed on to the TouchDevelop script. In addition, a script which implements an in-
teractive game needs to respond when the user taps certain items on the screen, and those taps can
also trigger events.
VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 81 –
The various kinds of events recognized by TouchDevelop are listed in Table 7.3. Sensors are cov-
ered in some more detail in Chapter 8 as well as more examples which use events. The events
grouped in the ‘Game Playing’ category will be covered only in Chapter 9.
Table 7.3: Events in TouchDevelop Scripts
Event Description
Phone Movement Events
shake Triggered when the phone is shaken
phone face up Triggered when the phone is turned so that it is face up
phone face down Triggered when the phone is turned so that it is face down
phone portrait Triggered when the phone is turned so the screen in portrait mode
(such as when the phone is vertical)
phone landscape left Triggered when the phone is turned so that its left side is facing
down
phone landscape right Triggered when the phone is turned so that its right side is facing
down
Media Events
active song changed
The names of these events describe the events camera button pressed
camera button half pressed
camera button released
Tap Wall Events
tap wall XX(item: XX)
XX represents any of the TouchDevelop datatypes, such as String or
Location or Number Map, etc. The event is triggered when a user
taps a display of a value of type XX on the wall (i.e. the screen). The
value is passed as a parameter to the event.
Game Playing Events
gameloop An event which is triggered by a timer approximately every 50ms
player state changed
tap board: b(x,y) Triggered when a global data item named b with type Board is
tapped; x and y are the coordinates of the tap.
swipe: board: b(x, y, dx, dy) Similar to tap board, except that it is triggered by a swiping action
starting at position x,y and with a distance vector dx,dy
tap sprite in s(sprite, index,
x, y)
Sprites will be covered in Chapter 9. (They are graphics objects
which can move around on the screen.)
swipe sprite in s(sprite, in-
dex, x, y, delta x, delta y)
drag sprite in s(sprite, in-
dex, x, y, delta x, delta y)
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 82 –
EXAMPLE EVENT HANDLING SCRIPT: PHONE ORIENTATION
A script can optionally include code which is executed whenever a particular kind of event happens.
As a simple example, let us construct a script which displays the words ‘Portrait’ and ‘Landscape’ in
large letters on the screen according to the phone’s current orientation.
To reuse some of the graphics code covered earlier in this chapter, we will create Picture values and
write text with suitable orientations for display into the pictures and display the pictures in the
event code.
The code for the main action and all three events is shown in Figure 7.5. As you can see, the main
action has got absolutely nothing to do. Even though control returns from the main action, the
script stays active waiting for events. The only way to stop this script is to tap the phone back but-
ton (or to tap the Windows button to exit from TouchDevelop completely).
Figure 7.5: Code for the Orientation Event Script
Two of the screen displays produced by this script as the phone is rotated are shown below in Fig-
ure 7.6.
VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 83 –
Figure 7.6: Some Output Displayed by the Orientation Script
7.3 GLOBAL DATA
Sometimes an event in a script needs to save information which is used later by an action or by an-
other invocation of an event (perhaps the same event, perhaps a different event). Where can such
information be saved? The only reasonable answer is to use a GLOBAL DATA VARIABLE. We have
already seen some example programs which use global data items. Let us look at one more.
EXAMPLE SCRIPT: A PEDOMETER
If you carry your Windows phone with you when jogging or walking briskly, the phone’s sensors
should trigger a SHAKE event each time you take one step. We can therefore write a simple script
which records how many steps you take, incrementing a counter each time the shake event occurs.
With a little more coding, we can compute the number of steps per minute. By using access to the
phone’s GPS location, we can also compute your average speed. However that programming feature
does not need to use any event code, so we will omit that feature in this version of the program.
When we begin creating the Pedometer script, TouchDevelop provides a default action named main
and that is all. No events and no global data items exist for the script. We could tap the plus button
to the right of the data icon to create a global data item for the number of steps taken, but let’s do it
another way. We can use the promote to global data item form of refactoring explained in Chapter 6.
The first thing we do in creating the script is to edit the code for the main action. We add the state-
ment
var steps := 0
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 84 –
where we have declared and initialized steps as a local variable. Now, by selecting this declaration
line for editing and selecting the left-hand side variable, we can promote it to a global data item
named ◳steps.
Similarly, we should declare
var start time := time→now
and then promote the start time local variable to be the global data item ◳start time. We need to
remember the time at which the script was started so that we can determine the elapsed time,
needed for computing the number of steps per minute.
The code for the Pedometer program is shown in Figure 7.6. The local variable elapsed is the time
since the script was started, measured in seconds. It is probably unnecessary to check that elapsed
has a non-zero value, but it is good programming practice to avoid division by zero. To compute the
walking or jogging rate as the number of steps per minute, we need to multiply the steps per second
by 60. Otherwise, the script should be easy to follow.
Figure 7.6: The Pedometer Script
Output from the script while it is running looks similar to that shown below.
This does not look very professional! Accuracy to 15 decimal places is just a bit excessive. Fortu-
nately it takes only one extra line of code to reduce the number of digits after to the decimal point
to a more reasonable number. Let’s pick one digit. If we insert either this line of code:
VERSION 1 BASIC GRAPHICS, EVENTS AND GLOBAL DATA
– 85 –
rate := math→round(10*rate)/10
or this line of code
rate := math→round with precision(rate,1)
after the line declaring and initializing the local variable rate, we will get just one digit to the right
of the decimal point. The output produced by the program now looks like this:
Now, why did we have to initialize ◳steps to zero in the main action? Why did it not just start with
the value 0 when we begin running the script? This is explained in the next subsection.
PERSISTENCE OF GLOBAL DATA VALUES
The very first time you use a script after it has been installed, the global data items will have initial
values which are 0 for Number values, false for Boolean values, an empty string for String values,
and date / time combination from long ago for DateTime values. For all other datatypes, the global
data item has the special INVALID value.
It may be necessary for the script to check and initialize global data variables to take account of first
time use of a script. The is invalid method is useful for checking the data items which start off with
an invalid value.
When the script is run a second time or a third time or …, the global data items still have the same
values as they had at the end of the previous run. In the terminology of programming languages, we
say that the values of the global data items PERSIST from one run to the next on your phone. Per-
sistence is a highly useful feature because it allows your scripts to accumulate information over
many runs. (In a misuse of the English language, programmers often say that a variable “is persist-
ed” if it retains its value from one run to the next .)
If you do not want to reuse a value from the previous run of the script, as is the case with the Pe-
dometer example, the script should re-initialize the global data items in whichever of its actions will
be invoked when the script is started. (This is likely to be every action which is not flagged as pri-
vate.)
BASIC GRAPHICS, EVENTS AND GLOBAL DATA VERSION 1
– 86 –