The second of a two part slide presentation showing how to make your own extensions for the Scratch programming environment. This goes quite deep so it's recommended that you view Part One before using this deck.
2. 2
T h e a u t h o r r e t a i n s
copyright of these slides.
You are free to use them so
long as the author’s name
i s q u o t e d o n a l l
presentations and excerpts.
ISS Tracker Scratch extension
code is provided with kind
permission of Kreg Hanning.
NOTE: occasional updates may be
p u b l i s h e d ( o n S l i d e S h a r e o r
elsewhere) from time to time.
Please check back for new versions.
Scratch is developed by the
Lifelong Kindergarten Group
at the MIT Media Lab.
See http://scratch.mit.edu
3. Introduction
Welcome back.
This is Part 2 of the slide set. Please refer back to Part 1 on SlideShare for info on
how we got here: http://www.slideshare.net/DarrenAdkinson/
understanding-scratchx-extensions-with-javascript
We’ll look briefly at two JS websites you might be interested in, then we’ll take a
look at how program control works with respect to blocks.
The rest of the presentation describes the individual functions in ISS Tracker.
This is definitely more advanced than Part 1 so you may need to re-read some
slides and do some background reading
3
4. Scratch2JS
4
The goal of this site is to
provide a path for kids
who are skilled in
Scratch and would like to
progress their coding
skills in a more powerful
direction.
http://s2js.com
5. 5
Also, code.org’s Hour of Code has a neat Star Wars task. It lets you code in
just block form (very similar to Scratch) or with a mixture of blocks and
typed, JavaScript, text. You can also switch between views.
Hour of Code - Star Wars in JavaScript
https://code.org/starwars
6. Types of Blocks
6
Generally blocks should either: (a) do
something quickly and, if applicable, get
back to us with an answer, or (b) allow
the calling function to provide a
“callback”*, so that slow operations
don’t need to hold everything up.
Ignore what the new blocks are doing for now.
In Scratch a block of code like the one on the
left runs sequentially from top to bottom (with
loops etc if used).
We need to ensure that blocks don’t hold up the
whole program.
*In spoken terms: “Ok, I’ll do what you asked me but it
could take some time. If you provide me with a way to
call you back I’ll give you a shout when it’s done”.
7. 7
Synchronous and Asynchronous Blocks
Use synchronous blocks for things like quick calculations or for accessing
local variables. Scratch will wait for them to finish before it moves on
with the next block - so they must be fast (non-blocking).
For anything that could take more than a few milliseconds, for instance
querying a database, connecting to a web server, etc then use an
asynchronous block.
In English, an asynchronous operation works something like this: “I’m
calling on you to do some work. I realize that part of your job could take
quite some time (maybe you won’t even get an answer) so I’m providing
you with a function that you can call back when you’ve handled this slow
part. So long as the rest of your code runs quickly you can return back to
me and we’ll handle the slow stuff separately when you call me back.”
8. 8
Timing in computers
The millisecond is a common unit of timing for computers. There are 1,000
milliseconds in a second. 1s = 1,000ms.
Below you can see the response times to a “ping” message sent to google (over the
web) and to my local machine (directly, on my laptop). It takes about 1/40th of a
sec (25ms) to get a simple ping to and from google’s server but it takes less than
1/10,000th of a sec (0.1ms) to get it to and from my own laptop - this is not at all
surprising as everything happens within my MacBook’s processor.
PING localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.061 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.090 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.068 ms
PING google.com (216.58.192.14): 56 data bytes
64 bytes from 216.58.192.14: icmp_seq=0 ttl=55 time=27.377 ms
64 bytes from 216.58.192.14: icmp_seq=1 ttl=55 time=25.733 ms
64 bytes from 216.58.192.14: icmp_seq=2 ttl=55 time=26.276 ms
Ping is a networking tool named from submarine sonar terminology
https://en.wikipedia.org/wiki/Ping_(networking_utility)
An online multiplayer game would need a round trip latency time of less than
170ms or so. Best would be lower than around 80ms.
A telephone call with a round trip delay of more than around 150ms (satellite,
usually) will be noticeably uncomfortable due to delayed voice.
9. 9
Callbacks
Asynchronous blocks use callbacks. In the list of parameters that you
give to this type of function usually the last one is a function and it’s
often called simply “callback”.
The callback is the function that you want the asynchronous block to -
literally - call back when it is ready to deliver something.
NOTE: the use of callbacks isn’t just related to making new Scratch
blocks; it’s part of JavaScript and some other languages. ISS Tracker
uses an asynchronous method (ext.distanceFrom) and an asynchronous
internal function (getLocation). In other words it might help to think
more about ‘blocks that make use JavaScript asynchronous functions’,
rather than ‘asynchronous blocks’.
10. 10
ISS Tracker - function landscape
One way to think of all the different functions in the program is to see
relationships, such as: who calls whom? who gives callbacks? who
writes and reads shared data, etc?
whenISSPasses
getISSInfodistanceFrom
getLocation updateISSLocationdistanceBetween
issData
locations
poller
api.wheretheiss.atnominatim.openstreetmap.org
provides a callback
supports callback
supports callback
provides a callback
provides a callback
called by ScratchX called by ScratchX
repeatedly polled
by ScratchX
‘R’ block ‘r’ block
‘hat’ block
used by callbacks
function call
write
read
www GET
part of callback
A
A
11. 11
upDateISSLocation
The crux of this extension is to show where the space station currently is.
As we saw in Part 1, a poller is set up to call the updateISSLocation
function about every 2s. When it gets valid data it writes that into the
issData variable.
Type this into a web browser and see what you get:
updateISSLocation
issData
poller
api.wheretheiss.at
A
https://api.wheretheiss.at/v1/satellites/25544
12. 12
upDateISSLocation
You should see text (pretty much human readable) like this:
{"name":"iss","id":25544,"latitude":49.659109059797,"longitude":55.137486529711,"altitude":
403.98632037339,"velocity":27637.357517735,"visibility":"eclipsed","footprint":
4425.0788235639,"timestamp":1454092225,"daynum":
2457417.2711227,"solar_lat":-17.929005746797,"solar_lon":265.66353626943,"units":"kilometers"}
We’ll cover the actual mechanism (using Ajax) later in these slides (see
slide 34). For now it’s good enough to know that this function goes off
to a web server and repeatedly updates our local data structure
(issData) with live information about the ISS.
Several other functions
read the data from
issData but nobody else
writes to it
(compartmentalizing is
nearly always a good
thing).
13. 13
upDateISSLocation
Here you can see that by adding a console.log statement you can get
output from the program and inspect it in your browser’s javascript
console (or dev tools).
It’s a good way to learn more about how things work internally.
Remember to take these out of production code as you can slow things
down a lot by adding log statements.
14. 14
getISSInfo
This method (a method is simply a property of an object that happens to
be a function) is called by Scratch when the block is processed.
getISSInfo
updateISSLocation
issData
poller
api.wheretheiss.at
called by ScratchX
‘r’ block
A
It’s an ‘r’ block, so it is
synchronous. This
means that it must do
its job quickly so as not
to delay processing.
It reads from the shared
data structure, issData.
15. 15
getISSInfo
If there is no valid data in issData then return, ie. no delay.
"latitude":49.659109059797
"longitude":55.137486529711
"altitude":403.98632037339
"velocity":27637.357517735
If there is valid data in issData then return the sub-
type of data that was requested, in String form,
with either six or two digits after the decimal
point.
Google “MDN toFixed”
and you should get a
link to this:
16. 16
whenISSPasses is a “hat” block.
We can split this discussion in two
parts: (a) how does a hat block work?
and (b) what does this particular hat
block do?
whenISSPasses
getLocation
issData
locations
nominatim.openstreetmap.org
provides a callback
supports callback
repeatedly polled
by ScratchX
‘hat’ block
whenISSPasses
17. 17
whenISSPasses
As a Scratch programmer you may well be used to hat blocks just doing
what you want: When green flag is clicked this block will become active,
etc.
As an extension writer you need to be aware of how a hat block is
implemented by the ScratchX environment.
If you think about the classic kid in a car: “Are we there yet? Are we
there yet? Are we there yet?” you’ll be on the right lines.
ScratchX will repeatedly call your hat block and it’s up to you to decide
if the hat block needs to come to life. Something like “Did it happen
yet?”
18. 18
whenISSPasses
I loaded the ISS
extension into a blank
project and used two
blocks. I added a log
statement so you can
see how frequesntly
the block is called by
ScratchX.
To see any logging you
need to give the hat
block something to
actually do otherwise
ScratchX won’t bother
polling it.
It gets polled about
every 20 - 50ms by
ScratchX.
19. 19
whenISSPasses
Note that in the last slide the pop sound wasn’t actually played since
my project was almost blank. I didn’t re-make Kreg’s whole Scratch
project so my test program knew nothing about the ISS, or Boston
for that matter. Had I re-made the project then the pop sound could
have been made to play, if I wanted to write the Scratch app that
way.
You can see that there is a lot of overhead that goes into providing
you, the extension programmer, with a way to write new hat blocks
for you extension’s users.
That more or less takes care of part (a) How do hat blocks work? So
how does this hat block work…
20. 20
whenISSPasses
About 25 times every second this method will be called (“polled”) by the
ScratchX environment.
If the issData object has nothing in it then the method simply returns (so
there’ll be no delay at all, effectively).
Usually, though, there will be some ISS data to work with.
‘Boston MA’, at least initially
21. 21
whenISSPasses
Stuff to do when called back
When there is some ISS data to work with this method then calls getLocation and
passes two parameters: a string (containing a place name, eg. Boston) and a
function that itself expects a parameter that it calls “loc”.
The function we pass as a parameter is anonymous and it is declared right there
inline where we call getLocation. This is a callback. So getLocation is going to get
on and do its job and, at some later point, it will call this callback function (and, we
trust, give it an argument).
getLocation could take hours, in theory, to do this. Program control just moves right
along to the next statement, hence we don’t cause delays in processing.
22. 22
Parameters versus Arguments
When you look at a function definition like:
function addTwoNum (a, b) { return (a+b); }
‘a’ and ‘b’ are function parameters: they are values (could be strings, arrays,
objects, booleans, whatever) that the function expects to be called with.
NOTE: JS is pretty loose in that you don’t have to call a function with all of its
parameters and you could even call it with more than it expects - it will silently
drop the extra ones.
var c = addTwoNum (3, 999);
When you see the function called with values passed in, these are called
arguments. In this case 3 and 999 are arguments.
NOTE: you’ll often see the two terms used interchangeably. I’ve probably done
it in these slides. It’s usually not a huge deal.
23. 23
Stuff to do when called back
whenISSPasses
We move on to the second ‘if’ statement now.
“locations” is a global object (global to this extension code at least) so we
ask if it has a value for the property of whatever “str” is. If it doesn’t we
just return false since we can’t say if the ISS is passing within a certain
distance of Boston if we don’t even know the lat/long of Boston.
Let’s look on the next slide at what the locations object actually looks
like when we use the default city of Boston.
24. 24
locations object
In your brower’s dev tool you can
most likely write code directly
into a script and then save it so
that it runs when the ISS
Tracker extension runs (in
Chrome on Mac OS X use cmd-S).
Here I added some log statements
to see the values of str and the
locations object (commented out
when I got the data).
locations is an object that can
contain a set of other objects:
currently it has just one object,
called Boston, MA.
The Boston, MA object
contains an array with two
values: lat and long and a
boolean property ‘overhead’.
25. 25
whenISSPasses
Stuff to do when called back
In this example locations[str] will hold a value so we move on to the
final return statement.
Also, at the time I ran the log statements, the ISS was not close to
Boston, MA, so the overhead property is false.
The result is that when the method is polled it returns false.
26. 26
getLocation
Let’s ignore this for a while and follow what happens when
whenISSPasses calls getLocation.
whenISSPasses
getLocation
locations
nominatim.openstreetmap.org
provides a callback
supports callback
27. 27
getLocation
If we get to this code then it
means we don’t have a
locations object for whatever
str is currently.
Here we use some ajax magic
to go out to the web and get
the lat & long for str.
We’ll cover this later…
getLocation accepts a callback function.
It’s called, strangely enough, “callback”
NOTE: we usually name
callback functions
“callback” *because*
they’re callback
functions.
They DO NOT become
callback functions
because we named them
that way; they could be
called “fred” if you
wanted, but the
convention is to do it
this way. Also they are
usually written last in
the parameter list.
28. 28
getLocation - callback to when ISSPasses
So let’s say we DO have a locations[str] object. In this case getLocation
becomes a lot simpler:
whenISSPasses
getLocation whenISSPasses
getLocation
provides a callback
supports callback
29. 29
getLocation
getLocation - callback to when ISSPasses
Now we call the callback function that was passed in as an argument.
We can finally start unpacking that “Stuff to do…”
whenISSPasses
callbafunc
str +
str +
allback
nct
Pack up the callback function and send
it over to getLocation, along with a
string (in this case, “Boston, MA”)
getLocation uses str and the callback
function as and when it needs to
since there is a locations[Boston, MA]
object we now ‘unpack’ the callback,
ie. call it, and hand control over to
the calling method. We pass back the
locations[Boston, MA] object as a
parameter of the callback function
30. 30
Important note about callbacks
Callbacks don’t necessarily always call back to the same calling method/
function. getLocation doesn’t care, but obviously you, the programmer,
should!
getLocation supports a callback and, if/when the time is right, will call
that callback function.
you’ll see that whenISSPasses and distanceFrom both make use of this
ability to send in a callback function as an argument to getLocation.
Callbacks are a very powerful mechanism.
31. 31
whenISSPasses -> distanceBetween
loc.coords[1] is the latitude of
Boston (about 42˚ N).
loc.coords[0] is the longitude of
Boston (about 71˚ E).
the unit we’re asking for is hard
coded to kilometers.
In simple terms this function works
out the distance between the ISS
right now and the location of
interest (which is Boston).
32. 32
distanceBetween
This is a neat little standalone
function: pass in a lat, long, and unit
and it will tell you how far the ISS is
away in those units.
It uses the Haversine formula to
calculate the distance between points.
See https://en.wikipedia.org/wiki/
Haversine_formula
Some notes if you want to dig into this:
most computers, mathematicians, engineers etc use radians as a measure of angle.
There are 2π radians in one full rotation, therefore 180˚ is equivalent to π rad and
each degree is π/180 rad.
Mozilla Developer Network (MDN) will tell you about Math methods sin, cos, sqrt,
round etc.
33. 33
whenISSPasses
getLocationdistanceBetween
supports callbackused in callbacks
distanceBetween
It was cheating a little to show the green arrows from getLocation to
distanceBetween as control actually goes back to whenISSPasses. That’s why those
green arrows were dashed.
The more accurate (but messier to display) control flow is shown below.
calls the callback
(when ready)returns a value
1
sets loc.overhead
2
calls
a
b
c
Part of whenISSPasses:
calls and gives
a callback
34. 34
whenISSPasses
getLocationdistanceBetween
supports callbackused in callbacks
distanceBetween
calls the callback
(when ready)returns a value
1
sets loc.overhead
calls and gives
a callback
2
calls
a
b
c
Part of whenISSPasses:
1
2
a
b
c
whenISSPasses calls getLocation with the two arguments
getLocation stores the callback function variable for later use, and then does its thing.
Control then returns back to the calling function.
time passes…
getLocation has something to report: it now calls the callback function
the callback function runs and calls distanceBetween
d
distanceBetween sends back a value
wISSPasses sets loc.overhead
d
35. 35
distanceBetween -> whenISSPasses
Finally, whenISSPasses gets an answer back from distanceBetween. It’s either
greater than 500km or it isn’t so we set the object’s “overhead” property
accordingly.
And this answers the persistent question that the ScratchX runtime environment is
nagging us for (polling) every 40ms or so: “Is it overhead yet?”
Much of the time it isn’t so the method’s return value will be false. Every so often it
will return true and then the regular Scratch blocks will be run until the ISS gets
too far away:
and so on…
37. 37
updateISSLocation redux
Going back to how we actually get the ISS location data it’s done with a JQuery
library call.
jQuery is a fast, small, and feature-rich JavaScript library.
In this function we’re using a jQuery Ajax* call to get data from the “wheretheiss”
server using a ‘GET’ request: https://api.wheretheiss.at
*Ajax describes a set of tools
that allow you to exchange
data with a server and then
update part of a web page
without requiring the whole
page to be refreshed. It makes
web pages very responsive.
38. 38
What is JQuery?
You can read all about jQuery here: https://jquery.com/
It’s the most popular JS library in use today.
A library in software is a set of subroutines, functions, programs, tools etc that
make part of your job easier. Some libraries are so ubiquitous they’re almost
thought of as part of a language.
Instead of typing JQuery() throughout code you can use the shorthand $()
39. 39
What is JSON?
JSON stands for JavaScript
Object Notation. It’s a way of
describing arbitrary data that
we want to share between
computers. It’s pretty much
human-readable.
Here’s an example from
www.sitepoint.com/colors-json-
example/
Note: JSON is used all over the web and with different
languages. It was derived from JS but most languages can
interpret and generate JSON-format data.
You don’t really need to understand JQuery, AJAX, or JSON in
any great depth to start making Scratch extensions but you
will need to know how to format a query and how to handle
the response.
40. 40
The jQuery AJAX method
The $.ajax()method contains many different options you can set in order to
specify how the ajax request should be made and handled.
The definitive place to get info is here: http://api.jquery.com/jQuery.ajax/
JQuery.ajax(url [,settings])
$.ajax(url [,settings])
optionalrequiredsame
meaning
url: which page we’re going to
type: either GET or POST
datatype: type of data you expect to
get back
success: a function that runs if the
Ajax request runs as expected
error: a function that runs if there
is an error with the Ajax request
41. 41
updateISSLocation redux
In summary, the jQuery ajax call says: “Go to server X and get me some JSON data.
If ok then set my global variable issData to be that data. If it goes wrong output an
error msg to the console log”.
http://api.jquery.com/jQuery.ajax/
It’s beyond the scope of this
presentation to go into detail
about all the $.ajax options but
you can see below the jQuery
description of the “error:” option.
In practice you can often get
away with ignoring it, at least
until you become more
experienced.
42. 42
distanceFrom
getLocation
supports callback
supports callback
provides a callback
provides a callback
called by ScratchX
distanceFrom
The distanceFrom method is an example of a chained callback. It is called by
ScratchX (because it’s a block method) and it’s given a callback (because it’s an ‘R’
block) and it uses a callback itself when it calls getLocation.
The internal callback part is almost exactly the same as the one we saw for
whenISSPasses, except that the unit of measurement isn’t hard coded to kilometers.
Remember we said earlier getLocation doesn’t care who gives it a callback - here we
see it supporting a callback from a different method.
43. 43
distanceBetween
used in callbacks
returns a value
distanceFrom
getLocation
supports callback
supports callback
ScratchX
1
a
calls the callback
(when ready)
2
sets loc.overhead
calls the callback
(when ready)
d
calls and gives a callback
calls
4
b
c
3
calls and gives
a callback
distanceFrom
1 2
3 4
a
b
c
d
synchronous
control flow
asynchronous
control flow
44. 44
distanceBetween
used in callbacks
returns a value
distanceFrom
getLocation
supports callback
supports callback
ScratchX
1
a
calls the callback
(when ready)
2
sets loc.overhead
calls the callback
(when ready)
d
calls and gives a callback
calls
4
b
c
3
calls and gives
a callback
distanceBetween
used in callbacks
returns a value
distanceFrom
getLocation
supports callback
supports callback
ScratchX
1
a
calls the callback
2
sets loc.overhead
calls the callback
d
calls and gives a callback
calls
4
b
c
3
calls and gives
t1
Another way to think about this is to look at the flow of time. At time t2 we see that the main flow of
control has passed beyond function calls (1), (2), (3) and (4) and now the first callback (a) is fired when
“getLocation” has something to report back to “distanceFrom”. So (b) is called, and the value is returned by (c)
and, finally, the callback to ScratchX (d) is invoked. This is what asynchronous flow is all about: stuff that
happens outside the regular, linear, flow of control.
time passes
t2
46. 46
Cross-domain Restrictions
Cross-domain restrictions are imposed as a security measure by browsers. They
prevent data being retrieved from a system other than the one that the original
page was served by.
In practice this means that a JSON request to a site other than ScratchX should
fail* - so we need a workaround.
The three main workarounds are: (a) use a proxy file on your server that gets data
from the outside server, (b) use CORS (cross origin resource sharing), (c) use JSONP,
called JSON with Padding. Of these three (a) and (b) are out of the scope of this
presentation.
JSONP involves adding a script element into the main request.
*So why does updateISSLocation work ok with a JSON request?
Frankly I don’t know. I haven’t yet found a satisfactory answer. Regardless, it’s still worth looking
at the workaround (my suspicion is that it relates to ScratchX running in Flash).
http://bob.ippoli.to/archives/2005/12/05/remote-json-jsonp/
47. 47
getLocation redux
Instead of a straightforward
request for JSON data from
the server we make a JSONP
request (Note: the server must
support this).
The code contains a call to a
function, json_callback, and
the JSON formatted data is
provided as an argument to
this function.
The server, because it supports
JSONP requests, calls the
callback and this is how the
JSON data gets back to us.
48. 48
ISS Tracker - function landscape
That’s everything. This is a repeat of Slide 10 but with slide numbers
added as a kind of index into what we discussed.
whenISSPasses
getISSInfodistanceFrom
getLocation updateISSLocationdistanceBetween
issData
locations
poller
api.wheretheiss.atnominatim.openstreetmap.org
provides a callback
supports callback
supports callback
provides a callback
provides a callback
called by ScratchX called by ScratchX
repeatedly polled
by ScratchX
‘R’ block ‘r’ block
‘hat’ block
used by callbacks
function call
write
read
www GET
part of callback
A
A
11 12 13
1514
-
24
-
31
-
- 4137
2516
26 293531
4342
-45 47
13
49. This was a lot deeper material and might take some re-reading with
a code printout beside it.
Constructive comments, ideas, suggestions, corrections, etc are
welcome.
GitHub username: darren-a
Email: dadkinson@gmail.com
49
Wrap Up