Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 472 lines (361 sloc) 23.942 kb
08598ba Init.
Michael Aufreiter authored
1 \begin{english}
2
3 \chapter{Unveil.js: A Data-driven Visualization Toolkit}
4 \label{cha:unveil}
5
6 % \section{Motivation}
7 %%%-----------------------------------------------------------------------------
8
e447a15 Minor fixes.
Michael Aufreiter authored
9 As described in Chapter~\ref{cha:web_based_visualization}, the HTML5 Canvas API is a low-level graphical system. It provides a number of drawing methods that can operate on a 2D pixel buffer. The fact that the Canvas API does not track objects implies that dependencies between them are not possible. A visualization's state (including the current set of data and commands issued by the user) can always be projected to a picture. Thus, the whole graphics buffer is refreshed on every frame. Visualization authors do not have to take care which objects need to be redrawn on a certain event. With Canvas, when a state change happens, the impact on the graphical representation is available on the next redraw (frame). If the same approach were applied with SVG, a lot of DOM manipulation would be necessary, resulting in poor performance. On the other hand, building complex visualizations without any kind of abstraction requires a lot of manual work and even leads to poor performance, if not optimized by hand.
08598ba Init.
Michael Aufreiter authored
10
11 Unveil.js is designed to combine the best of both worlds and introduces a slim \emph{layer of abstraction}, namely a \emph{Scene} interface that can be populated with graphical objects, the so called \emph{Actors}. It offers a simple programming interface for creating, updating and removing objects from the scene.
12
13 Unveil.js is an open source effort\footnote{http://github.com/michael/unveil} and is released under the MIT license.
14
15
16 \section{Goals}
17 %%%-----------------------------------------------------------------------------
18
19 Unveil.js is dedicated to Information Visualization and was built with respect to the following assumptions:
20
21 \begin{itemize}
22 \item
23 In most visualization scenarios the graphical display stays the same in periods where no interaction takes place.
24 \item
25 Most interactive visualizations feature transitions from one state to another.
26 \end{itemize}
27
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
28 \SuperPar Accordingly, most visualizations do not change state permanently. During periods when the state stays the same, there is no need for redraws. If there was a mechanism that detects state changes and triggers renderings on demand, the Canvas API could be used in very efficient ways. This would allow the creation of smooth animations involving a lot of moving objects while keeping the CPU utilization low, if no animation or interaction takes place.
08598ba Init.
Michael Aufreiter authored
29
30 There are a few considerations that need to be made. Interaction (like mouse movement) can trigger state changes. In cases where animation takes place, there must be subsequent re-renders on a high frame rate in order to make the transitions appear smoothly. Unveil.js implements a concept called \emph{Automatic Frame Rate Determination}. Based on the current state of the visualization, the frame rate can either be zero (no updates), low (during mouse interaction) or high (when animation is happening). Experiments have shown that by using this approach CPU consumption can be reduced remarkably. Compared to SVG the memory consumption is also kept low.
31
32 Unveil.js advocates a one-way dependency between input data and the resulting output image. Visualizations should be built in a way that every change of the internal state is immediately reflected on the output side. Using this approach, users do not have to deal with manual partial updates, a tedious and error-prone task. Unveil.js is considered to be a lightweight toolkit that helps managing complexity rather than being a full-featured graphical visualization library. It was designed to meet the following requirements:
33
34 \begin{itemize}
35 \item
36 \textbf{Object-oriented} in terms of thinking in graphical objects and modularizing code.
37 \item
38 \textbf{Declarative} in terms of using, configuring and combining existing Actors (graphical objects) and to attach them to the Scene.
39 \item
40 \textbf{Data-driven} to support a two-step mapping of data to an resulting image, involving an analytical abstraction and the transformation to visual objects.
41 \item
42 \textbf{Data Abstractions} for representation and manipulation of domain data.
43 \item
44 \textbf{Multiple Output Displays} for creating independent views on an abstract scene definition.
45 \item
46 \textbf{Automatic Frame Rate Determination} to reduce overall CPU consumption.
47 \item
48 \textbf{Dynamic Properties} allow functions to be used as property values, which are evaluated during runtime.
49 \item
50 \textbf{Interaction support} for mouse picking, zooming and panning.
51 \end{itemize}
52
53
54 \section{Specifying a Scene}
55 %%%-----------------------------------------------------------------------------
56
57 With Unveil.js, new visualizations are created by constructing a \texttt{Scene} object.
58
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
59 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
60 var scene = new uv.Scene();
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
61 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
62
63 \subsection{Actors}
64 %%%-----------------------------------------------------------------------------
65
66 Once the \texttt{Scene} object is ready, users can start adding \texttt{Actors}. An Actor can be a primitive graphical object (like a bar, a line, etc.) or a higher level object, which combines lower level ones (e.g. a snowman that is composed of three circles). Actors typically take graphical properties in their constructor. However, for higher level objects users probably want them to be constructed with \emph{real domain data} instead of graphical oriented properties (width, height, etc.). Users can decide on their own how they want to shape the interface of certain Actors.
67
68 \SuperPar The following code creates a bar instance, which will eventually be attached to the scene:
69
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
70 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
71 var bar = new uv.Bar({
72 id: 'outer_bar',
73 x: 30,
74 y: 50,
75 width: 30,
76 height: 80,
77 fillStyle: 'darkblue'
78 });
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
79 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
80
81 \SuperPar Each actor can hold any number of child actors, so another bar will be attached as a child to the parent bar.
82
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
83 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
84 bar.add(new uv.Bar({
85 id: 'inner_bar',
86 x: 50,
87 y: 20,
88 width: 20,
89 height: 80,
90 fillStyle: 'lightblue'
91 }));
92
93 scene.add(bar);
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
94 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
95
e447a15 Minor fixes.
Michael Aufreiter authored
96 \SuperPar The x and y coordinates are relative to the parent object. Thus, an object itself does not know where it is located in the coordinate-space. It just renders itself relative to the position of its parent. The positioning is done through \emph{matrix transformations}, where for each object the current context \emph{transformation matrix} (context) is calculated, which conforms to the functionality of a \emph{Scene Graph}.
08598ba Init.
Michael Aufreiter authored
97
98 \subsection{Output Displays}
99 %%%-----------------------------------------------------------------------------
100
101 Before a scene can be started, a display (or drawing surface) needs to be specified:
102
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
103 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
104 scene.display({
105 container: 'plotarea',
106 width: 800,
107 height: 300,
108 zooming: true,
109 paning: true
110 });
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
111 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
112
e447a15 Minor fixes.
Michael Aufreiter authored
113 \SuperPar Unveil.js uses an abstract scene (world-coordinates) that can be projected to one or many displays (canvas elements), which have a local coordinate system on their own. Each display can be modified (e.g. zoomed, paned) independently, which conforms to a view transformation in computer game engines (camera analogy). Once a display is set up, scenes can be started by calling the \texttt{start} method.
08598ba Init.
Michael Aufreiter authored
114
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
115 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
116 scene.start();
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
117 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
118
119 \SuperPar The scene automatically refreshes attached displays appropriately (on every frame), which implies that performance may decrease if multiple output displays are used.
120
121 \subsection{Implementing Custom Actors}
122 %%%-----------------------------------------------------------------------------
123
124 In addition to pre-implemented Actor types, users are encouraged to implement their own Actors suitable to their needs. In Unveil.js the creation of new actors forms a fundamental part of the \emph{Visualization Creation Process}.
125
126 \SuperPar In order to illustrate this, here is how the Bar Actor is implemented:
127
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
128 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
129 uv.Bar = function(properties) {
130 uv.Actor.call(this, _.extend({
131 width: 30,
132 height: 50,
133 strokeWeight: 2,
134 strokeStyle: '#000',
135 fillStyle: '#ccc'
136 }, properties));
137 };
138
139 uv.Bar.prototype = Object.extend(uv.Actor);
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
140 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
141
b7422b6 Use fancy code listings.
Michael Aufreiter authored
142 \SuperPar Every Actor inherits from \texttt{uv.Actor} and defines its own properties. In the case of \texttt{uv.Bar}, there is \texttt{width}, \texttt{height}, \texttt{strokeWeight}, \texttt{strokeStyle}, etc. Each Actor needs to know how it can draw itself. This is specified by the \texttt{draw} method that sticks on the Actor's prototype.
08598ba Init.
Michael Aufreiter authored
143
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
144 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
145 uv.Bar.prototype.draw = function(ctx) {
146 ctx.fillRect(0, 0, this.p('width'), this.p('height'));
147 };
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
148 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
149
150 \SuperPar Actors can not only form graphical objects but carry some state (e.g. domain data or user input) which is stored within the object. Such higher level objects can encapsulate behavior (like interactivity or animation) as well.
151
152
153 \subsection{Interaction}
154 %%%-----------------------------------------------------------------------------
155
e447a15 Minor fixes.
Michael Aufreiter authored
156 Interaction is a key-feature of modern visualizations. Therefore, Unveil.js aims to provide an abstraction for implementing interaction on Actors. Unlike in SVG, Canvas API users cannot attach event handlers to shapes directly. Instead, users need to detect on their own, i.e. which objects are currently under the cursor. Usually this is done by employing some math, but there is a simpler approach that utilizes the \texttt{isPointInPath} method provided by the Canvas API. With \texttt{isPointInPath}, users can check if the current mouse-position is inside the current working path. To support interaction, Unveil.js requires Actors to be equipped with an additional \texttt{drawMask} method.
08598ba Init.
Michael Aufreiter authored
157
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
158 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
159 uv.Bar.prototype.drawMask = function(ctx) {
160 ctx.beginPath();
161 ctx.moveTo(0, 0);
162 ctx.lineTo(this.properties.width, 0);
163 ctx.lineTo(this.properties.width, this.properties.height);
164 ctx.lineTo(0, this.properties.height);
165 ctx.lineTo(0, 0);
166 };
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
167 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
168
e447a15 Minor fixes.
Michael Aufreiter authored
169 \SuperPar This simply draws an invisible rectangle. If there are more complex objects, e.g. star-shapes, a rectangle (also known as a bounding-box) can be used as well to add interaction-awareness. All Actors that have a \texttt{drawMask} implementation can be easily checked against the current cursor position. For completeness, here is the corresponding code that is used internally to perform the actual hit testing.
08598ba Init.
Michael Aufreiter authored
170
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
171 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
172 uv.Actor.prototype.checkActive = function(ctx, mouseX, mouseY) {
173 if (this.drawMask && ctx.isPointInPath) {
174 this.drawMask(ctx);
175 if (ctx.isPointInPath(mouseX, mouseY))
176 this.active = true;
177 else
178 this.active = false;
179 }
180 };
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
181 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
182
183
184 \subsection{Event Handlers}
185 %%%-----------------------------------------------------------------------------
186
187 Given that interaction is supported for a certain actor, users are able to bind event handlers to certain events.
188
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
189 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
190 scene.get('inner_bar').bind('mouseover', function() {
191 this.p('fillStyle', 'red');
192 });
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
193 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
194
195 \SuperPar This example causes the inner bar to be colored red when the user's mouse cursor enters the object.
196
197 \subsection{Dynamic Properties}
198 %%%-----------------------------------------------------------------------------
199
200 Properties can not only takes values but also functions. During rendering, these functions are evaluated dynamically and their return value is taken as the property value.
201
202 \SuperPar Instead of specifying a mouseover handler to highlight certain objects, one could also use a dynamic property.
203
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
204 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
205 scene.get('inner_bar').p('fillStyle', function() {
206 return this.active ? 'red' : 'darkblue';
207 });
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
208 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
209
210
211 \subsection{Animation}
212 %%%-----------------------------------------------------------------------------
213
214 % maybe also suitable for the requirements section
215 In the context of Information Visualization, animation is often utilized in conjunction with state transitions. In other words, when the inner state (either data or user settings) changes, animation can be used to emphasize the transition from one state to another.
216
217 Based on new data, a visualization might assign new values to graphical objects, but wants to have this value interpolated over time, from the old value to the new value. Unveil.js users can call the \texttt{animate} method on Actors for that. The first parameter is a hash that contains the new property values. The second parameter determines the animation's duration, whereas the third parameter is optional and can be used to specify an easing function, which should be used for interpolation.
218
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
219 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
220 bar.animate({height: 50}, 2.5, uv.Tween.Easing.Expo.EaseInOut);
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
221 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
222
223 % Rendering depends on the current visualization state. As soon as interaction takes place or an animation gets started, subsequent re-renders get triggered automatically.
224
225 \subsection{Automatic Frame Rate Determination}
226 %%%-----------------------------------------------------------------------------
227
228 In order to spare CPU cycles, Unveil.js implements a \emph{Frame Rate On-demand Mechanism} to determine the current image refresh rate. This rate is either zero (idle mode) or high (during animation or interaction). It basically works like a semaphore, where each animation that is started increments a counter that keeps track of running frame rate requests. Once the animation has finished, this counter is decremented again. Interaction like mouse movement also increments that counter and decrements it after some time of inactivity. Unveil.js then triggers high-frequent redraws as soon as the counter exceeds zero.
229
230 \subsection{Matrix Transformations}
231 %%%-----------------------------------------------------------------------------
232
233 While most often specifying properties (x, y, scaleX, scaleY, rotation) on the Actor suffices, there may be cases where users need more control. For that purpose, Actors expose a so called \emph{Modification Matrix}, which can be directly modified by the user. Working with transformation matrices is a powerful tool and already common practice in game development and graphical programming.
234
235 \SuperPar For example, to scale and rotate around a given point in the coordinate system, a series of matrix transforms can be specified.
236
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
237 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
238 var b = new uv.Bar({...});
239 // move the coordinate system to the desired point
240 b.translate(40,40);
241 // scale around this point (= new origin)
242 b.scale(1.5, 1.5);
243 // rotate 45 degrees
244 b.rotate(Math.PI/4);
245 // move the coordinate system back
246 b.translate(-40, -40);
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
247 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
248
249 \SuperPar To calculate the resulting transformation matrix for drawing, it is initialized with the values of the specified properties and then multiplied with
250 the modification matrix.
251
252 \section{Data Abstractions}
253 \label{cha:dataabstractions}
254 %%%-----------------------------------------------------------------------------
255
e447a15 Minor fixes.
Michael Aufreiter authored
256 Unveil.js was built with a very data-centric approach in mind, offering a number of data abstraction utilities users can use for representing and manipulating domain data. For all data-related concerns Unveil.js relies on Data.js\footnote{http://substance.io/michael/data-js}, which is available as a separate library. Data.js is actively maintained and provides a range of features such as queries, filtering, clustering and serializable (thus exchangeable) data-formats. Tabular data can be represented through a \texttt{Data.Collection} interface, whereas complex linked data fits into the \texttt{Data.Graph} model. Not only data but also schema information can be inspected by the user, which can help building even more flexible data-driven visualizations. This can particularly be helpful for implementing \emph{Contextual Data Transformation} functionality, as described by Viegas et. al \cite{manyeyes}.
08598ba Init.
Michael Aufreiter authored
257
258 Here is an example of a \texttt{Data.Collection} containing real-world data about countries.
259
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
260 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
261 var countries_data = {
262 "properties": {
263 "name": {"name": "Country Name",
264 "type": "string", "unique": true },
265 "official_language": {"name": "Official Language",
266 "type": "string", "unique": true },
267 "population": { "name": "Population",
268 "type": "number", "unique": true },
269 "gdp": { "name": "GDP per capita",
270 "type": "number", "unique": true }
271 },
272 "items": {
273 "at": {
274 "name": "Austria",
275 "official_language": "German",
276 "population": 8356700,
277 "gdp": 39.761
278 },
279 "de": {
280 "name": "Germany",
281 "official_language": "German",
282 "population": 82062200,
283 "gdp": 46.860
284 },
285 "usa": {
286 "name": "United States of America",
287 "official_language": "English",
288 "population": 310955497,
289 "gdp": 36.081
290 }
291 }
292 };
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
293 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
294
e447a15 Minor fixes.
Michael Aufreiter authored
295 \SuperPar The collection shown above not only holds data for certain countries, but also contains meta-information, expressed as properties. As described in Chapter~\ref{cha:infovis}, this can be particularly useful for analytical and exploratory visualization tools.
08598ba Init.
Michael Aufreiter authored
296
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
297 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
298 languages.at(0).get('name'); // => "German"
299 languages.at(0).get('population') // => 90418900
300 languages.at(1).get('population') // => 310955497 for "English"
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
301 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
302
303 \subsection{Property Inspection}
304 %%%-----------------------------------------------------------------------------
305
306 Using the Property Inspection API, users can ask a certain property about its type, a human readable name or if it is unique (holding just one value) or not (holding a list of values).
307
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
308 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
309 countries.properties().get('population').type; // => 'number'
310 countries.properties().get('population').unique; // => false
311 countries.properties().get('population').name; // => 'Population'
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
312 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
313
314 \subsection{Aggregation}
315 %%%-----------------------------------------------------------------------------
316
317 Presumed that a user is interested in the populations grouped by language, the \texttt{Data.Collection.group()} method can be utilized. In order to aggregate the values of population, an aggregator function such as \texttt{Data.Aggregators.SUM} can be used.
318
e447a15 Minor fixes.
Michael Aufreiter authored
319 \pagebreak
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
320 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
321 var languages = countries.group(["official_language"], {
322 "population": {
323 aggregator: Data.Aggregators.SUM,
324 name: "Total Population"
325 }
326 });
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
327 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
328
329 \section{A Data-driven Bar Chart}
330 %%%-----------------------------------------------------------------------------
331
e447a15 Minor fixes.
Michael Aufreiter authored
332 In the following example, some real world domain data is used, namely countries containing information about their population and GDP per capita. These are visualized in a bar chart (Figure~\ref{fig:bars}). Users will be able to switch between different properties, triggering an animation from the old state to the new one.
08598ba Init.
Michael Aufreiter authored
333
334 \SuperPar The countries example from Section~\ref{cha:dataabstractions} will be used as a data-source.
335
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
336 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
337 var countries = new Data.Collection(countries_data);
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
338 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
339
340 \SuperPar The property that should be visually encoded is determined by the user using a select-box control. The HTML generated looks as follows:
341
342 \begin{verbatim}
343 <select id="property">
344 <option value="population">Population</option>
345 <option value="gdp">GDP per capita</option>
346 </select>
347 \end{verbatim}
348
349 \begin{figure}
350 \centering
351 \includegraphics[width=1\textwidth]{bars}
352 \caption{A data-driven barchart generated from domain data expressed as a \texttt{Data.Collection}}
353 \label{fig:bars}
354 \end{figure}
355
356 \SuperPar Furthermore, a Scene object is created complete with a specified output display:
357
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
358 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
359 var scene = new uv.Scene({
360 displays: [{
361 container: 'canvas',
362 width: 300,
363 height: 300
364 }]
365 });
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
366 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
367
368 \SuperPar In order to guarantee that the bars fit on the available screen space, they need to be normalized accordingly. The function shown below maps values from an input domain (real numbers) to an output range (pixels).
369
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
370 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
371 function y(val) {
372 var dMax = countries.properties().get(property)
373 .aggregate(Data.Aggregators.MAX),
374 oMax = 200;
375 return parseInt(val/dMax * oMax);
376 }
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
377 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
378
379
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
380 \SuperPar The scene will be initialized by adding a bar per data element in the collection. The height property encodes the value of the property under investigation.
b7422b6 Use fancy code listings.
Michael Aufreiter authored
381
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
382 \begin{verbatim}
383 countries.items().each(function(c, key, index) {
384 scene.add({
385 id: "country_"+key,
386 type: 'rect',
387 x: 50+35*index,
388 y: 280,
389 width: 30,
390 height: -parseInt(y(c.get(property)), 10),
391 fillStyle: function() {
392 return this.active ? 'orange' : 'blue';
393 },
394 interactive: true,
e447a15 Minor fixes.
Michael Aufreiter authored
395 actors: [{
396 type: 'label',
397 x: 15,
398 y: 20,
399 width: 30,
400 height: 20,
401 text: function() { return c._id.toUpperCase() },
402 textAlign: 'center',
403 fillStyle: '#444'
404 }]
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
405 });
406 });
407 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
408
409 \SuperPar Additionally, the visualization should allow dynamic switching between properties. For that purpose, property inspection features provided by Data.js are used to find out which numeric properties are available for the collection. By doing so, the visualization can be used with arbitrary collections, even if their structure differs.
410
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
411 \begin{verbatim}
e447a15 Minor fixes.
Michael Aufreiter authored
412 countries.properties().each(function(p) {
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
413 if (p.type === "number" && p.unique) {
414 var option = $('<option value="'+p.key+'">'+p.name+'</option>');
415 $('#property').append(option);
416 }
417 });
418 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
419
e447a15 Minor fixes.
Michael Aufreiter authored
420 \SuperPar Every time the user selects a property, the bars need to be updated accordingly. In an event handler the \texttt{animate} method is used to specify an animated transition of the bar's height.
08598ba Init.
Michael Aufreiter authored
421
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
422 \begin{verbatim}
08598ba Init.
Michael Aufreiter authored
423 function update() {
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
424 property = $('#property').val();
08598ba Init.
Michael Aufreiter authored
425 countries.items().each(function(c, key, index) {
426 scene.get("country_"+key).animate({
427 height: -parseInt(y(c.get(property)), 10)
428 }, 1.0);
429 });
430 }
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
431 $('#property').change(update);
432 \end{verbatim}
08598ba Init.
Michael Aufreiter authored
433
434 \SuperPar Finally, the scene can be started.
435
45a3453 Roll back to \verbatim.
Michael Aufreiter authored
436 \begin{verbatim}
437 scene.start();
438 \end{verbatim}
439
08598ba Init.
Michael Aufreiter authored
440
441 \section{Example Applications}
442 %%%-----------------------------------------------------------------------------
443
444
445 There is a range of examples available, that show different applications of Unveil.js. For each of them, the source code is available for inspection.
446
447 \subsection{Scatterplot}
448 %%%-----------------------------------------------------------------------------
449
450 \begin{figure}
451 \centering
452 \includegraphics[width=1\textwidth]{scatterplot}
453 \caption{Scatterplot: A zoomable scatterplot visualization showing indicators for countries in three dimensions encoded using x-Axis, y-Axis and dot size.}
454 \label{fig:scatterplot}
455 \end{figure}
456
457 Scatterplot\footnote{http://github.com/michael/scatterplot}, as shown in Figure \ref{fig:scatterplot}, is an implementation of a zoomable scatterplot visualization that takes data in a uniform \texttt{Data.Collection} format. Users can assign different properties to certain axes. Each time they are changed, an animated transition takes place. Scatterplot makes intensive use of the data manipulation utilities provided by Data.js as well as matrix transformations for implementing zoom and pan behavior.
458
459
460 \subsection{Stacks}
461 %%%-----------------------------------------------------------------------------
462
e447a15 Minor fixes.
Michael Aufreiter authored
463 Stacks\footnote{http://github.com/michael/stacks}, as shown in Figure \ref{fig:stacks}, is a visualization of categorical data. Musical artists are displayed using self-organizing stacks that hold items of a certain group (e.g. genres like pop music, jazz, etc.). Based on meta-data, users can choose from ordinal properties that should be used to calculate group memberships. Transitions are animated accordingly.
08598ba Init.
Michael Aufreiter authored
464
465 \begin{figure}
466 \centering
467 \includegraphics[width=1\textwidth]{stacks}
468 \caption{Self-organizing Stacks: Based on a layout algorithm groups and items are arranged on the screen.}
469 \label{fig:stacks}
470 \end{figure}
471
472 \end{english}
Something went wrong with that request. Please try again.