65
and height of an image, which will make the browser shrink or enlarge the image, but
that technique is not demonstrated here.)
The ability to dynamically replace one image with another in an HTML document
opens the door to a number of special effects. One common use for image replacement
is to implement image rollovers, in which an image changes when the mouse pointer
moves over it. When you make images clickable by placing them inside your hyperlinks,
rollover effects are a powerful way to invite the user to click on the image. (Similar
effects can be achieved without scripting using the CSS
:hover
pseudoclass to alter the
background image of an element.) The following HTML fragment is a simple example:
it creates an image that changes when the mouse moves over it:
<img src="images/help.gif"
onmouseover="this.src='images/help_rollover.gif'"
onmouseout="this.src='images/help.gif'">
The event handlers of the
<img>
element set the
src
property when the mouse moves
over or out of the image. Image rollovers are strongly associated with clickability, so
this
<img>
element should still be enclosed in an
<a>
element or given an
onclick
event
handler.
In order to be useful, image rollovers (and similar effects) need to be responsive. This
means that you need some way to ensure that the necessary images are “prefetched”
into the browser’s cache. Client-side JavaScript defines a special-purpose API for this
purpose: to force an image to be cached, create an offscreen Image object using the
Image()
constructor. Next, load an image into it by setting the
src
property of this object
to the desired URL. This image is not added to the document, so it does not become
visible, but the browser nevertheless loads and caches the image data. Later, when the
same URL is used for an onscreen image, it can be quickly loaded from the browser’s
cache, rather than slowly loaded over the network.
The image-rollover code fragment shown in the previous section did not prefetch the
rollover image it used, so the user might notice a delay in the rollover effect the first
time she moves the mouse over the image. To fix this problem, modify the code as
follows:
<script>(new Image()).src = "images/help_rollover.gif";</script>
<img src="images/help.gif"
onmouseover="this.src='images/help_rollover.gif'"
onmouseout="this.src='images/help.gif'">
21.1.1 Unobtrusive Image Rollovers
The image rollover code just shown requires one
<script>
element and two JavaScript
event-handler attributes to implement a single rollover effect. This is a perfect example
of obtrusive JavaScript: the amount of JavaScript code is so large that it effectively
obscures the HTML. Example 21-1 shows an unobtrusive alternative that allows you
to create image rollovers by simply specifying a
data-rollover
attribute (see §15.4.3)
on any
<img>
element. Note that this example uses the
onLoad()
function of Exam-
614 | Chapter 21: Scripted Media and Graphics
58
ple 13-5. It also uses the
document.images[]
array (see §15.2.3) to find all
<img>
elements
in the document.
Example 21-1. Unobtrusive Image Rollovers
/**
* rollover.js: unobtrusive image rollovers.
*
* To create image rollovers, include this module in your HTML file and
* use the data-rollover attribute on any <img> element to specify the URL of
* the rollover image. For example:
*
* <img src="normal_image.png" data-rollover="rollover_image.png">
*
* Note that this module requires onLoad.js
*/
onLoad(function() { // Everything in one anonymous function: no symbols defined
// Loop through all images, looking for the data-rollover attribute
for(var i = 0; i < document.images.length; i++) {
var img = document.images[i];
var rollover = img.getAttribute("data-rollover");
if (!rollover) continue; // Skip images without data-rollover
// Ensure that the rollover image is in the cache
(new Image()).src = rollover;
// Define an attribute to remember the default image URL
img.setAttribute("data-rollout", img.src);
// Register the event handlers that create the rollover effect
img.onmouseover = function() {
this.src = this.getAttribute("data-rollover");
};
img.onmouseout = function() {
this.src = this.getAttribute("data-rollout");
};
}
});
21.2 Scripting Audio and Video
HTML5 introduces
<audio>
and
<video>
elements that are, in theory, as easy to use as
the
<img>
element. In HTML5-enabled browsers, you no longer need to use plug-ins
(like Flash) to embed sounds and movies in your HTML documents:
<audio src="background_music.mp3"/>
<video src="news.mov" width=320 height=240/>
In practice, the use of these elements is trickier than this, since browser vendors have
not been able to agree on a standard audio and video codec that all will support, so you
typically end up using
<source>
elements to specify multiple media sources in different
formats:
21.2 Scripting Audio and Video | 615
Client-Side
JavaScript
76
<audio id="music">
<source src="music.mp3" type="audio/mpeg">
<source src="music.ogg" type='audio/ogg; codec="vorbis"'>
</audio>
Note that
<source>
elements have no content: there is no closing
</source>
tag, and
you do not need to end them with
/>
Browsers that support
<audio>
and
<video>
elements will not render these element’s
content. But browsers that do not support them do render their content, so you can
put fallback content (such as an
<object>
element that invokes the Flash plug-in) inside:
<video id="news" width=640 height=480 controls preload>
<!-- WebM format for Firefox and Chrome -->
<source src="news.webm" type='video/webm; codecs="vp8, vorbis"'>
<!-- H.264 format for IE and Safari -->
<source src="news.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
<!-- Fall back on the Flash plugin -->
<object width=640 height=480 type="application/x-shockwave-flash"
data="flash_movie_player.swf">
<!-- Param elements here configure the Flash movie player you're using -->
<!-- Text is the ultimate fallback content -->
<div>video element not supported and Flash plugin not installed.</div>
</object>
</video>
<audio>
and
<video>
elements support a
controls
attribute. If present (or if the corre-
sponding JavaScript property is set to
true
), they display a set of playback controls that
includes play and pause buttons, a volume control, and so on. In addition, however,
the
<audio>
and
<video>
elements expose an API that gives scripts the power to control
media playback, and you can use this API to add simple sound effects to your web
application or to create your own custom control panels for sound and video. Although
their visual appearance is very different, the
<audio>
and
<video>
elements share es-
sentially the same API (the only real difference between them is that the
<video>
element
has
width
and
height
properties) and almost everything that follows in this section
applies to both elements.
The Audio() constructor
<audio>
elements don’t have any visual appearance in the document unless you set the
controls
attribute. And just as you can create an offscreen image with the
Image()
constructor, the HTML5 media API allows you to create an offscreen audio element
with the
Audio()
constructor, passing a source URL as the argument:
new Audio("chime.wav").play(); // Load and play a sound effect
616 | Chapter 21: Scripted Media and Graphics
75
The return value of the
Audio()
constructor is the same kind of object you’d get when
querying an
<audio>
element from the document, or creating a new one with
document.createElement("audio")
. Note that this is an audio-only feature of the media
API: there is no corresponding
Video()
constructor.
Despite the frustrating requirement to define media in multiple file formats, the ability
to play audio and video natively in the browser, without the use of plug-ins, is a pow-
erful new feature in HTML5. Note that the problem of media codecs and browser
compatibility is beyond the scope of this book. The subsections that follow focus only
on the JavaScript API for working with audio and video streams.
21.2.1 Type Selection and Loading
If you want to test whether a media element can play a particular type of media, pass
the media MIME type (possibly including a
codec
parameter) to the
canPlayType()
method. The element returns the empty string (a falsy value) if it cannot play that media
type. Otherwise, it returns the string “maybe” or “probably”. Because of the compli-
cated nature of audio and video codecs, a player cannot in general be more certain than
“probably” that it can play a particular media type without actually downloading the
media and trying:
var a = new Audio();
if (a.canPlayType("audio/wav")) {
a.src = "soundeffect.wav";
a.play();
}
When you set the
src
property of a media element, it begins the process of loading that
media. (That process won’t go very far unless
preload
is “auto”.) Setting
src
when some
other media is loading or playing will abort the loading or playing of the old media. If
you add
<source>
elements to a media element instead of setting the
src
attribute, the
element cannot know when you have inserted a complete set of elements, and it will
not begin choosing among the
<source>
elements and loading data until you explicitly
call the
load()
method.
21.2.2 Controlling Media Playback
The most important methods of the
<audio>
and
<video>
elements are
play()
and
pause()
, which start and stop playback of the media:
// When the document has loaded, start playing some background music
window.addEventListener("load", function() {
document.getElementById("music").play();
}, false);
In addition to starting and stopping sound and video, you can skip (or “seek”) to a
desired location within the media by setting the
currentTime
property. This property
specifies the time in seconds to which the player should skip, and it can be set while
21.2 Scripting Audio and Video | 617
Client-Side
JavaScript
How to C#: Basic SDK Concept of XDoc.PDF for .NET You may add PDF document protection functionality into your C# of PDF document, including editing PDF url links and quick navigation link in bookmark
add a link to a pdf; add links to pdf acrobat VB.NET PDF: Basic SDK Concept of XDoc.PDF You may add PDF document protection functionality into your VB.NET of PDF document, including editing PDF url links and quick navigation link in bookmark
clickable links in pdf files; add page number to pdf hyperlink
142
the media is playing or while it is paused. (The
initialTime
and
duration
properties
give the legal range of values for
currentTime
; more about those properties follows.)
The
volume
property specifies playback volume as a number between 0 (silent) and 1
(maximum volume). The
muted
property can be set to
true
to mute playback or set to
false
to resume playing sound at the specified
volume
level.
The
playbackRate
property specifies the speed at which the media is played. A value of
1.0 is the normal speed. Values greater than 1 are “fast forward” and values between 0
and 1 are “slow motion.” Negative values are supposed to play the sound or video
backward, but browsers do not support that feature at the time of this writing.
<audio>
and
<video>
elements also have a
defaultPlaybackRate
property. Whenever the
play()
method is invoked, the
playbackRate
property is set to
defaultPlaybackRate
.
Note that the
currentTime
,
volume
,
muted
, and
playbackRate
properties are not only for
controlling media playback. If an
<audio>
or
<video>
element has the
controls
attribute,
it displays player controls, giving the user control over playback. In that case, a script
might query properties like
muted
and
currentTime
to discover how the media is being
played.
The HTML attributes
controls
,
loop
,
preload
, and
autoplay
affect audio and video
playback and can also be set and queried as JavaScript properties.
controls
specifies
whether playback controls are displayed in the browser. Set this property to
true
to
display controls or
false
to hide controls. The
loop
property is a boolean that specifies
whether the media should play in a loop (
true
) or stop when it reaches the end
(
false
). The
preload
property specifies whether (or how much) media content should
be preloaded before the user starts playing the media. The value “none” means no data
should be preloaded. The value “metadata” means that metadata such as duration,
bitrate, and frame size should be loaded, but not media data itself. Browsers typically
load metadata if you do not specify a
preload
attribute. The
preload
value “auto” means
that the browser should preload as much of the media as it deems appropriate. Finally,
the
autoplay
property specifies whether the media should begin to play automatically
when a sufficient amount has been buffered. Setting
autoplay
to
true
obviously implies
that the browser should preload media data.
21.2.3 Querying Media Status
<audio>
and
<video>
elements have a number of read-only properties that describe the
current state of the media and of the player.
paused
is
true
if the player is paused.
seeking
is
true
if the player is skipping to a new playback position.
ended
is
true
if the
player has reached the end of the media and has stopped. (
ended
never becomes
true
if
loop
is true.)
The
duration
property specifies the duration of the media in seconds. If you query this
property before the media metadata has been loaded, it returns
NaN
. For streaming
media, such as Internet radio, with an indefinite duration, this property returns
Infinity
.
618 | Chapter 21: Scripted Media and Graphics
104
The
initialTime
property specifies the start time of the media, in seconds. For media
clips of fixed duration, this is usually 0. For streaming media, this property gives the
earliest time for which data is still buffered and which it is possible to seek back to.
currentTime
can never be set to less than
initialTime
.
Three other properties provide a finer-grained view of the media timeline and its play-
back and buffering status. The
played
property returns the time range or ranges that
have been played. The
buffered
property returns the time range or ranges that are
currently buffered, and the
seekable
property returns the time range or ranges that the
player can currently seek to. (You might use these properties to implement a progress
bar that illustrates the
currentTime
and
duration
along with how much of the media
has played and how much is buffered.)
played
,
buffered
, and
seekable
are
TimeRanges
objects. Each object has a
length
prop-
erty that specifies the number of ranges it represents and
start()
and
end()
methods
that return the start and end times (in seconds) of a numbered range. In the most
common case of a single contiguous range of times, you’d use
start(0)
and
end(0)
.
Assuming that no seeking has happened and media is buffered from the beginning, for
example, you might use code like this to determine what percentage of a resource was
buffered:
var percent_loaded = Math.floor(song.buffered.end(0) / song.duration * 100);
Finally, three more properties,
readyState
,
networkState
, and
error
, give low-level sta-
tus details about
<audio>
and
<video>
elements. Each of the properties has a numeric
value, and constants are defined for each of the legal values. Note that these constants
are defined on the media object (or the error object) itself. You might use one in code
like this:
if (song.readyState === song.HAVE_ENOUGH_DATA) song.play();
readyState
specifies how much media data has been loaded, and therefore, how ready
the element is to begin playing that data. The values for this property and their meanings
are as follows:
Constant
Value
Description
HAVE_NOTHING
0
No media data or metadata has been loaded.
HAVE_METADATA
1
The media metadata has been loaded, but no data for the current playback position
has been loaded. This means that you can query the
duration
of the media or the
dimensions of a video and you can seek by setting
currentTime
, but the browser
cannot currently play the media at
currentTime
.
HAVE_CURRENT_DATA
2
Media data for
currentTime
has been loaded, but not enough data has been
loaded to allow the media to play. For video, this typically means that the current
frame has loaded, but the next one has not. This state occurs at the end of a sound
or movie.
HAVE_FUTURE_DATA
3
Enough media data has been loaded to begin playing, but it is likely not enough to
play to the end of the media without pausing to download more data.
21.2 Scripting Audio and Video | 619
Client-Side
JavaScript
89
Constant
Value
Description
HAVE_ENOUGH_DATA
4
Enough media data has been loaded that the browser is likely to be able to play to
the end without pausing.
The
networkState
property specifies whether (or why not) a media element is using the
network:
Constant
Value
Description
NETWORK_EMPTY
0
The element has not started using the network. This would be the state before the
src
attribute was set, for example.
NETWORK_IDLE
1
The element is not currently loading data from the network. It might have loaded
the complete resource, or might have buffered all the data it currently needs. Or it
might have
preload
set to “none” and not yet have been asked to load or play the
media.
NETWORK_LOADING
2
The element is currently using the network to load media data.
NETWORK_NO_SOURCE
3
The element was not able to find a media source that it is able to play.
When an error occurs in media loading or playback, the browser sets the
error
property
of the
<audio>
or
<video>
element. If no error has occurred,
error
is
null
. Otherwise,
it is an object with a numeric
code
property that describes the error. The error object
also defines constants that describe the possible error codes:
Constant
Value
Description
MEDIA_ERR_ABORTED
1
The user asked the browser to stop loading the media
MEDIA_ERR_NETWORK
2
The media is of the right type, but a network error prevented it from
being loaded.
MEDIA_ERR_DECODE
3
The media is of the right type, but an encoding error prevented it from
being decoded and played.
MEDIA_ERR_SRC_NOT_SUPPORTED
4
The media specified by the
src
attribute is not a type that the browser
can play.
You might use the
error
property with code like this:
if (song.error.code == song.error.MEDIA_ERR_DECODE)
alert("Can't play song: corrupt audio data.");
21.2.4 Media Events
<audio>
and
<video>
are fairly complex elements—they must respond to user interac-
tion with their playback controls, to network activity, and even, during playback, to
the simple passage of time—and we’ve just seen that these elements have quite a few
properties that define their current state. Like most HTML elements,
<audio>
and
<video>
fire events whenever their state changes. Because these elements have such a
complicated state, they can fire quite a few events.
620 | Chapter 21: Scripted Media and Graphics
Download from Wow! eBook <www.wowebook.com>
127
The table below summarizes the 22 media events, loosely in the order in which they
are likely to occur. There are no event registration properties for these events. Use the
addEventListener()
method of the
<audio>
or
<video>
element to register handler
functions.
Event Type
Description
loadstart
Triggered when the element begins requesting media data.
networkState
is
NETWORK_LOADING
.
progress
Network activity is continuing to load media data.
networkState
is
NETWORK_LOADING
. Typ-
ically fired between 2 and 8 times per second.
loadedmetadata
The media metadata has been loaded, and the duration and dimensions of the media are ready.
readyState
has changed to
HAVE_METADATA
for the first time.
loadeddata
Data for the current playback position has loaded for the first time, and
readyState
has changed
to
HAVE_CURRENT_DATA
.
canplay
Enough media data has loaded that playback can begin, but additional buffering is likely to be
required.
readyState
is
HAVE_FUTURE_DATA
.
canplaythrough
Enough media data has loaded that the media can probably be played all the way through without
pausing to buffer more data.
readyState
is
HAVE_ENOUGH_DATA
.
suspend
The element has buffered enough data and has temporarily stopped downloading.
network
State
has changed to
NETWORK_IDLE
.
stalled
The element is trying to load data, but no data is arriving.
networkState
remains at
NETWORK_LOADING
.
play
The
play()
method has been invoked, or the
autoplay
attribute has caused the equivalent. If
sufficient data has loaded, this event will be followed by a playing event. Otherwise a waiting event
will follow.
waiting
Playback cannot begin, or playback has stopped, because there is not enough data buffered. A playing
event will follow when enough data is ready.
playing
The media has begun to play.
timeupdate
The
currentTime
property has changed. During normal playback, this event is fired between 4
and 60 times per second, possibly depending on system load and how long the event handlers are
taking to complete.
pause
The
pause()
method was called and playback has been paused.
seeking
The script or user has requested that playback skip to an unbuffered portion of the media and playback
has stopped while data loads. The
seeking
property is
true
.
seeked
The
seeking
property has changed back to
false
.
ended
Playback has stopped because the end of the media has been reached.
durationchange
The
duration
property has changed
volumechange
The
volume
or
muted
property has changed.
ratechange
The
playbackRate
or
defaultPlaybackRate
has changed.
abort
The element has stopped loading data, typically at the user’s request.
error.code
is
MEDIA_ERR_ABORTED
.
21.2 Scripting Audio and Video | 621
Client-Side
JavaScript
55
Event Type
Description
error
A network or other error prevented media data from being loaded.
error.code
is a value other
than
MEDIA_ERR_ABORTED
.
emptied
An error or abort has caused the
networkState
to return to
NETWORK_EMPTY
.
21.3 SVG: Scalable Vector Graphics
SVG is an XML grammar for graphics. The word “vector” in its name indicates that it
is fundamentally different from raster image formats, such as GIF, JPEG, and PNG,
that specify a matrix of pixel values. Instead, an SVG “image” is a precise, resolution-
independent (hence “scalable”) description of the steps necessary to draw the desired
graphic. Here is what a simple SVG file looks like:
<!-- Begin an SVG figure and declare our namespace -->
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 1000"> <!-- Coordinate system for figure -->
<defs> <!-- Set up some definitions we'll use -->
<linearGradient id="fade"> <!-- a color gradient named "fade" -->
<stop offset="0%" stop-color="#008"/> <!-- Start a dark blue -->
<stop offset="100%" stop-color="#ccf"/> <!-- Fade to light blue -->
</linearGradient>
</defs>
<!-- Draw a rectangle with a thick black border and fill it with the fade -->
<rect x="100" y="200" width="800" height="600"
stroke="black" stroke-width="25" fill="url(#fade)"/>
</svg>
Figure 21-1 shows what this SVG file looks like when rendered graphically.
SVG is a large and moderately complex grammar. In addition to simple shape-drawing
primitives, it includes support for arbitrary curves, text, and animation. SVG graphics
can even incorporate JavaScript scripts and CSS stylesheets to add behavior and pre-
sentation information. This section shows how client-side JavaScript code (embedded
in HTML, not in SVG) can dynamically draw graphics using SVG. It includes examples
of SVG drawing but can only scratch the surface of what is possible with SVG. Full
details about SVG are available in the comprehensive, but quite readable, specification.
The specification is maintained by the W3C at http://www.w3.org/TR/SVG/. Note that
the specification includes a complete Document Object Model for SVG documents.
This section manipulates SVG graphics using the standard XML DOM and does not
use the SVG DOM at all.
At the time of this writing, all current browsers except IE support SVG (and IE9 will
support it). In the latest browsers, you can display SVG images using an ordinary
<img>
element. Some slightly older browsers (such as Firefox 3.6) do not support this
and require the use of an
<object>
element:
<object data="sample.svg" type="image/svg+xml" width="100" height="100"/>
622 | Chapter 21: Scripted Media and Graphics
Documents you may be interested
Documents you may be interested