├── .gitignore
├── Cakefile
├── examples
├── budgetForecast
│ ├── annotation.js
│ ├── data.js
│ ├── index.html
│ ├── timeline.js
│ └── vis.js
├── habemusPapam
│ ├── ellipsis.js
│ ├── external-link.png
│ └── index.html
├── lib
│ ├── colorbrewer
│ │ ├── LICENSE
│ │ ├── colorbrewer.css
│ │ └── colorbrewer.js
│ ├── d3.v2.js
│ ├── jquery-ui
│ │ ├── LICENSE
│ │ ├── images
│ │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png
│ │ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ │ ├── ui-bg_flat_75_ffffff_40x100.png
│ │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png
│ │ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ │ ├── ui-bg_glass_75_dadada_1x400.png
│ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png
│ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png
│ │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png
│ │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ │ ├── ui-icons_222222_256x240.png
│ │ │ ├── ui-icons_228ef1_256x240.png
│ │ │ ├── ui-icons_2e83ff_256x240.png
│ │ │ ├── ui-icons_454545_256x240.png
│ │ │ ├── ui-icons_888888_256x240.png
│ │ │ ├── ui-icons_cd0a0a_256x240.png
│ │ │ ├── ui-icons_ef8c08_256x240.png
│ │ │ ├── ui-icons_ffd27a_256x240.png
│ │ │ └── ui-icons_ffffff_256x240.png
│ │ ├── jquery-ui.css
│ │ └── jquery-ui.min.js
│ ├── jquery
│ │ ├── LICENSE
│ │ ├── jquery.js
│ │ └── jquery.min.js
│ └── n3.js
└── unemployment
│ ├── annualRates.js
│ ├── choropleth.js
│ ├── data
│ ├── annualData.json
│ ├── counties-unemployment.json
│ ├── county-ids.json
│ ├── states-unemployment.json
│ ├── us-counties.json
│ ├── us-states.json
│ └── validLocationIds.js
│ ├── index.html
│ ├── scenes.js
│ └── unemployment.css
├── n3.js
├── package.json
├── src
├── annotation.coffee
├── scene.coffee
├── state.coffee
├── timeline.coffee
├── trigger.coffee
├── util.coffee
├── version.coffee
└── vis.coffee
├── test
├── annotation.test.coffee
├── domTimingTest.html
├── scene.test.coffee
├── support
│ ├── jasmine.yml
│ ├── jasmine_config.rb
│ └── jasmine_runner.rb
├── timeline.test.coffee
├── trigger.test.coffee
└── vis.test.coffee
└── ui
├── css
├── colorpicker.css
├── jquery-ui.css
├── n3-edit.css
└── n3-play.css
├── imgs
├── accept.png
├── add-large.png
├── add.png
├── bind_data.png
├── blank.gif
├── colorpicker_background.png
├── colorpicker_hex.png
├── colorpicker_hsb_b.png
├── colorpicker_hsb_h.png
├── colorpicker_hsb_s.png
├── colorpicker_indic.gif
├── colorpicker_overlay.png
├── colorpicker_rgb_b.png
├── colorpicker_rgb_g.png
├── colorpicker_rgb_r.png
├── colorpicker_select.gif
├── colorpicker_submit.png
├── custom_background.png
├── custom_hex.png
├── custom_hsb_b.png
├── custom_hsb_h.png
├── custom_hsb_s.png
├── custom_indic.gif
├── custom_rgb_b.png
├── custom_rgb_g.png
├── custom_rgb_r.png
├── custom_submit.png
├── delete.png
├── drag-handle.png
├── draw-circle.png
├── draw-ellipse.png
├── draw-line.png
├── draw-rect.png
├── draw-text.png
├── edit.png
├── export.png
├── play.png
├── select.png
├── select2.png
├── slider.png
├── state.png
├── styles.png
├── trigger-empty.png
├── trigger.png
├── ui-bg_diagonals-thick_18_b81900_40x40.png
├── ui-bg_diagonals-thick_20_666666_40x40.png
├── ui-bg_flat_0_aaaaaa_40x100.png
├── ui-bg_flat_10_000000_40x100.png
├── ui-bg_flat_30_cccccc_40x100.png
├── ui-bg_flat_50_5c5c5c_40x100.png
├── ui-bg_flat_75_ffffff_40x100.png
├── ui-bg_glass_100_f6f6f6_1x400.png
├── ui-bg_glass_100_fdf5ce_1x400.png
├── ui-bg_glass_20_555555_1x400.png
├── ui-bg_glass_40_0078a3_1x400.png
├── ui-bg_glass_40_ffc73d_1x400.png
├── ui-bg_glass_55_fbf9ee_1x400.png
├── ui-bg_glass_65_ffffff_1x400.png
├── ui-bg_glass_75_dadada_1x400.png
├── ui-bg_glass_75_e6e6e6_1x400.png
├── ui-bg_glass_95_fef1ec_1x400.png
├── ui-bg_gloss-wave_25_333333_500x100.png
├── ui-bg_gloss-wave_35_f6a828_500x100.png
├── ui-bg_highlight-soft_100_eeeeee_1x100.png
├── ui-bg_highlight-soft_75_cccccc_1x100.png
├── ui-bg_highlight-soft_75_ffe45c_1x100.png
├── ui-bg_highlight-soft_80_eeeeee_1x100.png
├── ui-bg_inset-soft_25_000000_1x100.png
├── ui-bg_inset-soft_30_f58400_1x100.png
├── ui-icons_222222_256x240.png
├── ui-icons_228ef1_256x240.png
├── ui-icons_2e83ff_256x240.png
├── ui-icons_454545_256x240.png
├── ui-icons_4b8e0b_256x240.png
├── ui-icons_888888_256x240.png
├── ui-icons_a83300_256x240.png
├── ui-icons_cccccc_256x240.png
├── ui-icons_cd0a0a_256x240.png
├── ui-icons_ef8c08_256x240.png
├── ui-icons_ffd27a_256x240.png
├── ui-icons_ffffff_256x240.png
└── widget.png
├── index.html
├── js
├── colorpicker.js
├── d3.min.js
├── jquery-ui.min.js
├── jquery.chromatable.js
├── jquery.getPath.js
├── jquery.json-2.3.min.js
├── jquery.min.js
├── n3-edit.js
├── n3-play.js
└── n3.js
└── play.html
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .jhw-cache
--------------------------------------------------------------------------------
/Cakefile:
--------------------------------------------------------------------------------
1 | fs = require 'fs'
2 | {print} = require 'util'
3 | {spawn, exec} = require 'child_process'
4 |
5 | task 'build', 'compile coffee files and concatenate', ->
6 | files = ['version', 'util', 'state', 'vis', 'annotation', 'trigger',
7 | 'scene', 'timeline']
8 |
9 | args = ['--compile', '--join', 'n3.js']
10 | args.push "src/#{file}.coffee" for file in files
11 |
12 | coffee = spawn 'coffee', args
13 | coffee.stdout.on 'data', (data) -> print data.toString()
14 | coffee.stderr.on 'data', (data) -> print data.toString()
15 |
16 |
17 | task 'test', 'test against the specs', ->
18 | args = ['-c', '-j', 'test/support/jasmine.yml']
19 | jasmine = spawn 'jasmine-headless-webkit', args
20 | jasmine.stdout.on 'data', (data) -> print data.toString()
21 | jasmine.stderr.on 'data', (data) -> print data.toString()
--------------------------------------------------------------------------------
/examples/budgetForecast/annotation.js:
--------------------------------------------------------------------------------
1 | n3.annotation.def('highlightedPoint')
2 | .enter(function() {
3 | var vis = this.vis();
4 | var sx = vis.const('sx')();
5 | var sy = vis.const('sy')();
6 |
7 |
8 | var point = vis.stage().selectAll('circle.point')
9 | .data(this.data(), function(d) { return d.budgetYear; });
10 |
11 | point.enter()
12 | .append('svg:circle')
13 | .attr('class', 'point')
14 | .attr('cx', function(d) { return sx(d.forecastYear) })
15 | .attr('cy', function(d) { return sy(d.value) })
16 | .attr('r', 2.5);
17 |
18 | point.transition()
19 | .attr('cx', function(d) { return sx(d.forecastYear) })
20 | .attr('cy', function(d) { return sy(d.value) });
21 |
22 | point.exit().remove();
23 |
24 | var annotCircle = vis.stage().selectAll('circle.annotation')
25 | .data(this.data());
26 |
27 | annotCircle.enter()
28 | .append('svg:circle')
29 | .attr('class', 'annotation')
30 | .attr('cx', function(d) { return sx(d.forecastYear) })
31 | .attr('cy', function(d) { return sy(d.value) })
32 | .attr('r', 7);
33 |
34 | annotCircle.transition()
35 | .attr('cx', function(d) { return sx(d.forecastYear) })
36 | .attr('cy', function(d) { return sy(d.value) });
37 |
38 | annotCircle.exit().remove();
39 | })
40 | .exit(function() {
41 | var vis = this.vis();
42 | vis.stage().selectAll('circle.point').remove();
43 | vis.stage().selectAll('circle.annotation').remove();
44 | });
45 |
46 |
--------------------------------------------------------------------------------
/examples/budgetForecast/data.js:
--------------------------------------------------------------------------------
1 | var fullData = [
2 | {"budgetYear": 1980, "forecastYear": 1980, "value": -103},
3 | {"budgetYear": 1980, "forecastYear": 1981, "value": -37},
4 | {"budgetYear": 1980, "forecastYear": 1982, "value": 10},
5 | {"budgetYear": 1980, "forecastYear": 1983, "value": 51},
6 | {"budgetYear": 1981, "forecastYear": 1980, "value": -192},
7 | {"budgetYear": 1981, "forecastYear": 1981, "value": -129},
8 | {"budgetYear": 1981, "forecastYear": 1982, "value": -60},
9 | {"budgetYear": 1981, "forecastYear": 1983, "value": -17},
10 | {"budgetYear": 1981, "forecastYear": 1984, "value": 63},
11 | {"budgetYear": 1982, "forecastYear": 1981, "value": -185},
12 | {"budgetYear": 1982, "forecastYear": 1982, "value": -215},
13 | {"budgetYear": 1982, "forecastYear": 1983, "value": -190},
14 | {"budgetYear": 1982, "forecastYear": 1984, "value": -164},
15 | {"budgetYear": 1982, "forecastYear": 1985, "value": -137},
16 | {"budgetYear": 1983, "forecastYear": 1982, "value": -280},
17 | {"budgetYear": 1983, "forecastYear": 1983, "value": -432},
18 | {"budgetYear": 1983, "forecastYear": 1984, "value": -373},
19 | {"budgetYear": 1983, "forecastYear": 1985, "value": -371},
20 | {"budgetYear": 1983, "forecastYear": 1986, "value": -275},
21 | {"budgetYear": 1984, "forecastYear": 1983, "value": -432},
22 | {"budgetYear": 1984, "forecastYear": 1984, "value": -363},
23 | {"budgetYear": 1984, "forecastYear": 1985, "value": -345},
24 | {"budgetYear": 1984, "forecastYear": 1986, "value": -330},
25 | {"budgetYear": 1984, "forecastYear": 1987, "value": -326},
26 | {"budgetYear": 1984, "forecastYear": 1988, "value": -267},
27 | {"budgetYear": 1984, "forecastYear": 1989, "value": -209},
28 | {"budgetYear": 1985, "forecastYear": 1984, "value": -367},
29 | {"budgetYear": 1985, "forecastYear": 1985, "value": -425},
30 | {"budgetYear": 1985, "forecastYear": 1986, "value": -336},
31 | {"budgetYear": 1985, "forecastYear": 1987, "value": -298},
32 | {"budgetYear": 1985, "forecastYear": 1988, "value": -253},
33 | {"budgetYear": 1985, "forecastYear": 1989, "value": -182},
34 | {"budgetYear": 1985, "forecastYear": 1990, "value": -135},
35 | {"budgetYear": 1986, "forecastYear": 1985, "value": -406},
36 | {"budgetYear": 1986, "forecastYear": 1986, "value": -378},
37 | {"budgetYear": 1986, "forecastYear": 1987, "value": -260},
38 | {"budgetYear": 1986, "forecastYear": 1988, "value": -164},
39 | {"budgetYear": 1986, "forecastYear": 1989, "value": -114},
40 | {"budgetYear": 1987, "forecastYear": 1986, "value": -412},
41 | {"budgetYear": 1987, "forecastYear": 1987, "value": -313},
42 | {"budgetYear": 1987, "forecastYear": 1988, "value": -189},
43 | {"budgetYear": 1987, "forecastYear": 1989, "value": -157},
44 | {"budgetYear": 1987, "forecastYear": 1990, "value": -98},
45 | {"budgetYear": 1987, "forecastYear": 1991, "value": -33},
46 | {"budgetYear": 1987, "forecastYear": 1992, "value": 19},
47 | {"budgetYear": 1988, "forecastYear": 1987, "value": -271},
48 | {"budgetYear": 1988, "forecastYear": 1988, "value": -257},
49 | {"budgetYear": 1988, "forecastYear": 1989, "value": -219},
50 | {"budgetYear": 1988, "forecastYear": 1990, "value": -166},
51 | {"budgetYear": 1988, "forecastYear": 1991, "value": -124},
52 | {"budgetYear": 1988, "forecastYear": 1992, "value": -77},
53 | {"budgetYear": 1988, "forecastYear": 1993, "value": -34},
54 | {"budgetYear": 1989, "forecastYear": 1988, "value": -272},
55 | {"budgetYear": 1989, "forecastYear": 1989, "value": -273},
56 | {"budgetYear": 1989, "forecastYear": 1990, "value": -152},
57 | {"budgetYear": 1989, "forecastYear": 1991, "value": -105},
58 | {"budgetYear": 1989, "forecastYear": 1992, "value": -49},
59 | {"budgetYear": 1989, "forecastYear": 1993, "value": -4},
60 | {"budgetYear": 1989, "forecastYear": 1994, "value": 48},
61 | {"budgetYear": 1990, "forecastYear": 1989, "value": -258},
62 | {"budgetYear": 1990, "forecastYear": 1990, "value": -203},
63 | {"budgetYear": 1990, "forecastYear": 1991, "value": -99},
64 | {"budgetYear": 1990, "forecastYear": 1992, "value": -38},
65 | {"budgetYear": 1990, "forecastYear": 1993, "value": 8},
66 | {"budgetYear": 1990, "forecastYear": 1994, "value": 15},
67 | {"budgetYear": 1990, "forecastYear": 1995, "value": 13},
68 | {"budgetYear": 1991, "forecastYear": 1990, "value": -363},
69 | {"budgetYear": 1991, "forecastYear": 1991, "value": -499},
70 | {"budgetYear": 1991, "forecastYear": 1992, "value": -424},
71 | {"budgetYear": 1991, "forecastYear": 1993, "value": -296},
72 | {"budgetYear": 1991, "forecastYear": 1994, "value": -89},
73 | {"budgetYear": 1991, "forecastYear": 1995, "value": 4},
74 | {"budgetYear": 1991, "forecastYear": 1996, "value": 27},
75 | {"budgetYear": 1992, "forecastYear": 1991, "value": -422},
76 | {"budgetYear": 1992, "forecastYear": 1992, "value": -603},
77 | {"budgetYear": 1992, "forecastYear": 1993, "value": -514},
78 | {"budgetYear": 1992, "forecastYear": 1994, "value": -306},
79 | {"budgetYear": 1992, "forecastYear": 1995, "value": -272},
80 | {"budgetYear": 1992, "forecastYear": 1996, "value": -249},
81 | {"budgetYear": 1992, "forecastYear": 1997, "value": -252},
82 | {"budgetYear": 1993, "forecastYear": 1992, "value": -438},
83 | {"budgetYear": 1993, "forecastYear": 1993, "value": -465},
84 | {"budgetYear": 1993, "forecastYear": 1994, "value": -367},
85 | {"budgetYear": 1993, "forecastYear": 1995, "value": -323},
86 | {"budgetYear": 1993, "forecastYear": 1996, "value": -258},
87 | {"budgetYear": 1993, "forecastYear": 1997, "value": -243},
88 | {"budgetYear": 1994, "forecastYear": 1993, "value": -375},
89 | {"budgetYear": 1994, "forecastYear": 1994, "value": -339},
90 | {"budgetYear": 1994, "forecastYear": 1995, "value": -232},
91 | {"budgetYear": 1994, "forecastYear": 1996, "value": -233},
92 | {"budgetYear": 1994, "forecastYear": 1997, "value": -250},
93 | {"budgetYear": 1994, "forecastYear": 1998, "value": -253},
94 | {"budgetYear": 1994, "forecastYear": 1999, "value": -238},
95 | {"budgetYear": 1995, "forecastYear": 1994, "value": -293},
96 | {"budgetYear": 1995, "forecastYear": 1995, "value": -270},
97 | {"budgetYear": 1995, "forecastYear": 1996, "value": -270},
98 | {"budgetYear": 1995, "forecastYear": 1997, "value": -286},
99 | {"budgetYear": 1995, "forecastYear": 1998, "value": -261},
100 | {"budgetYear": 1995, "forecastYear": 1999, "value": -259},
101 | {"budgetYear": 1995, "forecastYear": 2000, "value": -249},
102 | {"budgetYear": 1996, "forecastYear": 1995, "value": -230},
103 | {"budgetYear": 1996, "forecastYear": 1996, "value": -200},
104 | {"budgetYear": 1996, "forecastYear": 1997, "value": -188},
105 | {"budgetYear": 1996, "forecastYear": 1998, "value": -130},
106 | {"budgetYear": 1996, "forecastYear": 1999, "value": -84},
107 | {"budgetYear": 1996, "forecastYear": 2000, "value": -35},
108 | {"budgetYear": 1996, "forecastYear": 2001, "value": 10},
109 | {"budgetYear": 1996, "forecastYear": 2002, "value": 54},
110 | {"budgetYear": 1997, "forecastYear": 1996, "value": -147},
111 | {"budgetYear": 1997, "forecastYear": 1997, "value": -169},
112 | {"budgetYear": 1997, "forecastYear": 1998, "value": -160},
113 | {"budgetYear": 1997, "forecastYear": 1999, "value": -154},
114 | {"budgetYear": 1997, "forecastYear": 2000, "value": -112},
115 | {"budgetYear": 1997, "forecastYear": 2001, "value": -45},
116 | {"budgetYear": 1997, "forecastYear": 2002, "value": 21},
117 | {"budgetYear": 1998, "forecastYear": 1997, "value": -29},
118 | {"budgetYear": 1998, "forecastYear": 1998, "value": -13},
119 | {"budgetYear": 1998, "forecastYear": 1999, "value": 12},
120 | {"budgetYear": 1998, "forecastYear": 2000, "value": 11},
121 | {"budgetYear": 1998, "forecastYear": 2001, "value": 35},
122 | {"budgetYear": 1998, "forecastYear": 2002, "value": 110},
123 | {"budgetYear": 1998, "forecastYear": 2003, "value": 98},
124 | {"budgetYear": 1998, "forecastYear": 2004, "value": 127},
125 | {"budgetYear": 1998, "forecastYear": 2005, "value": 153},
126 | {"budgetYear": 1998, "forecastYear": 2006, "value": 178},
127 | {"budgetYear": 1998, "forecastYear": 2007, "value": 228},
128 | {"budgetYear": 1999, "forecastYear": 1998, "value": 92},
129 | {"budgetYear": 1999, "forecastYear": 1999, "value": 104},
130 | {"budgetYear": 1999, "forecastYear": 2000, "value": 150},
131 | {"budgetYear": 1999, "forecastYear": 2001, "value": 167},
132 | {"budgetYear": 1999, "forecastYear": 2002, "value": 229},
133 | {"budgetYear": 1999, "forecastYear": 2003, "value": 218},
134 | {"budgetYear": 1999, "forecastYear": 2004, "value": 242},
135 | {"budgetYear": 2000, "forecastYear": 1999, "value": 165},
136 | {"budgetYear": 2000, "forecastYear": 2000, "value": 214},
137 | {"budgetYear": 2000, "forecastYear": 2001, "value": 230},
138 | {"budgetYear": 2000, "forecastYear": 2002, "value": 229},
139 | {"budgetYear": 2000, "forecastYear": 2003, "value": 221},
140 | {"budgetYear": 2000, "forecastYear": 2004, "value": 227},
141 | {"budgetYear": 2000, "forecastYear": 2005, "value": 241},
142 | {"budgetYear": 2000, "forecastYear": 2006, "value": 277},
143 | {"budgetYear": 2000, "forecastYear": 2007, "value": 308},
144 | {"budgetYear": 2000, "forecastYear": 2008, "value": 320},
145 | {"budgetYear": 2000, "forecastYear": 2009, "value": 334},
146 | {"budgetYear": 2000, "forecastYear": 2010, "value": 363},
147 | {"budgetYear": 2001, "forecastYear": 2000, "value": 302},
148 | {"budgetYear": 2001, "forecastYear": 2001, "value": 351},
149 | {"budgetYear": 2001, "forecastYear": 2002, "value": 284},
150 | {"budgetYear": 2001, "forecastYear": 2003, "value": 290},
151 | {"budgetYear": 2001, "forecastYear": 2004, "value": 305},
152 | {"budgetYear": 2001, "forecastYear": 2005, "value": 302},
153 | {"budgetYear": 2001, "forecastYear": 2006, "value": 331},
154 | {"budgetYear": 2001, "forecastYear": 2007, "value": 359},
155 | {"budgetYear": 2001, "forecastYear": 2008, "value": 380},
156 | {"budgetYear": 2001, "forecastYear": 2009, "value": 427},
157 | {"budgetYear": 2001, "forecastYear": 2010, "value": 465},
158 | {"budgetYear": 2001, "forecastYear": 2011, "value": 519},
159 | {"budgetYear": 2002, "forecastYear": 2001, "value": 160},
160 | {"budgetYear": 2002, "forecastYear": 2002, "value": -130},
161 | {"budgetYear": 2002, "forecastYear": 2003, "value": -96},
162 | {"budgetYear": 2002, "forecastYear": 2004, "value": -16},
163 | {"budgetYear": 2002, "forecastYear": 2005, "value": 68},
164 | {"budgetYear": 2002, "forecastYear": 2006, "value": 93},
165 | {"budgetYear": 2002, "forecastYear": 2007, "value": 110},
166 | {"budgetYear": 2003, "forecastYear": 2002, "value": -194},
167 | {"budgetYear": 2003, "forecastYear": 2003, "value": -364},
168 | {"budgetYear": 2003, "forecastYear": 2004, "value": -357},
169 | {"budgetYear": 2003, "forecastYear": 2005, "value": -233},
170 | {"budgetYear": 2003, "forecastYear": 2006, "value": -218},
171 | {"budgetYear": 2003, "forecastYear": 2007, "value": -188},
172 | {"budgetYear": 2003, "forecastYear": 2008, "value": -193},
173 | {"budgetYear": 2004, "forecastYear": 2003, "value": -452},
174 | {"budgetYear": 2004, "forecastYear": 2004, "value": -606},
175 | {"budgetYear": 2004, "forecastYear": 2005, "value": -409},
176 | {"budgetYear": 2004, "forecastYear": 2006, "value": -290},
177 | {"budgetYear": 2004, "forecastYear": 2007, "value": -254},
178 | {"budgetYear": 2004, "forecastYear": 2008, "value": -243},
179 | {"budgetYear": 2004, "forecastYear": 2009, "value": -241},
180 | {"budgetYear": 2005, "forecastYear": 2004, "value": -480},
181 | {"budgetYear": 2005, "forecastYear": 2005, "value": -479},
182 | {"budgetYear": 2005, "forecastYear": 2006, "value": -423},
183 | {"budgetYear": 2005, "forecastYear": 2007, "value": -329},
184 | {"budgetYear": 2005, "forecastYear": 2008, "value": -255},
185 | {"budgetYear": 2005, "forecastYear": 2009, "value": -237},
186 | {"budgetYear": 2005, "forecastYear": 2010, "value": -207},
187 | {"budgetYear": 2006, "forecastYear": 2005, "value": -357},
188 | {"budgetYear": 2006, "forecastYear": 2006, "value": -458},
189 | {"budgetYear": 2006, "forecastYear": 2007, "value": -373},
190 | {"budgetYear": 2006, "forecastYear": 2008, "value": -227},
191 | {"budgetYear": 2006, "forecastYear": 2009, "value": -211},
192 | {"budgetYear": 2006, "forecastYear": 2010, "value": -183},
193 | {"budgetYear": 2006, "forecastYear": 2011, "value": -202},
194 | {"budgetYear": 2007, "forecastYear": 2006, "value": -269},
195 | {"budgetYear": 2007, "forecastYear": 2007, "value": -257},
196 | {"budgetYear": 2007, "forecastYear": 2008, "value": -240},
197 | {"budgetYear": 2007, "forecastYear": 2009, "value": -190},
198 | {"budgetYear": 2007, "forecastYear": 2010, "value": -94},
199 | {"budgetYear": 2007, "forecastYear": 2011, "value": -53},
200 | {"budgetYear": 2007, "forecastYear": 2012, "value": 59},
201 | {"budgetYear": 2008, "forecastYear": 2007, "value": -170},
202 | {"budgetYear": 2008, "forecastYear": 2008, "value": -417},
203 | {"budgetYear": 2008, "forecastYear": 2009, "value": -414},
204 | {"budgetYear": 2008, "forecastYear": 2010, "value": -160},
205 | {"budgetYear": 2008, "forecastYear": 2011, "value": -94},
206 | {"budgetYear": 2008, "forecastYear": 2012, "value": 47},
207 | {"budgetYear": 2008, "forecastYear": 2013, "value": 28},
208 | {"budgetYear": 2009, "forecastYear": 2008, "value": -467},
209 | {"budgetYear": 2009, "forecastYear": 2009, "value": -1781},
210 | {"budgetYear": 2009, "forecastYear": 2010, "value": -1171},
211 | {"budgetYear": 2009, "forecastYear": 2011, "value": -899},
212 | {"budgetYear": 2009, "forecastYear": 2012, "value": -563},
213 | {"budgetYear": 2009, "forecastYear": 2013, "value": -507},
214 | {"budgetYear": 2009, "forecastYear": 2014, "value": -532},
215 | {"budgetYear": 2009, "forecastYear": 2015, "value": -534},
216 | {"budgetYear": 2009, "forecastYear": 2016, "value": -573},
217 | {"budgetYear": 2009, "forecastYear": 2017, "value": -562},
218 | {"budgetYear": 2009, "forecastYear": 2018, "value": -551},
219 | {"budgetYear": 2009, "forecastYear": 2019, "value": -607},
220 | {"budgetYear": 2010, "forecastYear": 2009, "value": -1436},
221 | {"budgetYear": 2010, "forecastYear": 2010, "value": -1556},
222 | {"budgetYear": 2010, "forecastYear": 2011, "value": -1250},
223 | {"budgetYear": 2010, "forecastYear": 2012, "value": -803},
224 | {"budgetYear": 2010, "forecastYear": 2013, "value": -692},
225 | {"budgetYear": 2010, "forecastYear": 2014, "value": -659},
226 | {"budgetYear": 2010, "forecastYear": 2015, "value": -689},
227 | {"budgetYear": 2010, "forecastYear": 2016, "value": -700},
228 | {"budgetYear": 2010, "forecastYear": 2017, "value": -688},
229 | {"budgetYear": 2010, "forecastYear": 2018, "value": -682},
230 | {"budgetYear": 2010, "forecastYear": 2019, "value": -775},
231 | {"budgetYear": 2010, "forecastYear": 2020, "value": -841}
232 | ];
--------------------------------------------------------------------------------
/examples/budgetForecast/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NYTimes Porcupine Graph
5 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
1
91 |
2
92 |
3
93 |
4
94 |
5
95 |
6
96 |
97 |
98 |
99 |
100 |
Falling Short
101 |
102 |
President Obama's budget proposal estimates a deficit of $1.6 trillion for the current fiscal year and $1.3 trillion in 2011.
103 |
104 |
105 |
106 |
Forecasts worsen
107 |
108 |
The forecast for the next decade is somewhat worse than it was a year ago, mostly because of a revised economic outlook. From 2011 to 2020, a total deficit of $8.5 trillion is expect
109 |
110 |
111 |
112 |
Past forecasts
113 |
114 |
Even that may be an understatement. In the last 30 years, about 80 percent of four-year deficit forecasts have been too optimistic.
115 |
The early Clinton budgets — which failed to predict the surpluses that were generated, in part, by a stock market bubble — are the only major exception
116 |
117 |
118 |
119 |
Past forecasts
120 |
121 |
In contrast, just two years ago, the Bush administration projected a surplus by 2012.
122 |
123 |
124 |
125 |
Latest forecast
126 |
127 |
Today, with a better understanding of the severity of the economic downturn, the deficit situation is much more dire.
128 |
129 |
130 |
131 |
Reasons for error
132 |
133 |
Budget forecasts require assumptions about both policy and the economy, and both can turn out to be spectacularly wrong.
134 |
In 2008, for example, the unemployment rate in 2012 was assumed to be 4.8 percent. The most recent assumption is 8.2 percent.
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/examples/budgetForecast/timeline.js:
--------------------------------------------------------------------------------
1 | vis.bind('year', function(val) {
2 | $('#slider').slider('value', val);
3 | })
4 |
5 | n3.scene('scene_1')
6 | .set(vis, 'year', 2010)
7 | .set(vis, 'plotForecasts', false)
8 |
9 | .add(vis, function() { // Init jQuery slider
10 | $('#slider').slider({
11 | min: 1980,
12 | max: 2010,
13 | step: 1,
14 | slide: function(e, ui) {
15 | vis.state('year', ui.value);
16 | }
17 | });
18 |
19 | $('#slider').hide();
20 | })
21 |
22 | .add(vis,
23 | n3.annotation('highlightedPoint')
24 | .data([fullData[219], fullData[220]]))
25 |
26 | .add(vis,
27 | n3.annotation('label')
28 | .attr('id', 'lbl_2010')
29 | .html('2010 estimate:-$1.56 trillion
')
30 | .pos([540, 341]))
31 |
32 | .add(vis,
33 | n3.annotation('label')
34 | .attr('id', 'lbl_2011')
35 | .html('2011 proposal:-$1.27 trillion
')
36 | .pos([560, 280]));
37 |
38 | n3.scene('scene_2')
39 | .set(vis, 'year', 2010)
40 | .set(vis, 'plotForecasts', false)
41 |
42 | .add(vis, function() {
43 | var drawLineGraph = vis.const('drawLineGraph')();
44 | var dataTransform = vis.const('dataTransform');
45 | var year = 2009;
46 | var data = [];
47 | var fullData = vis.data();
48 |
49 | for(var i in fullData) {
50 | var d = fullData[i];
51 | if(d.budgetYear != year)
52 | continue;
53 |
54 | data[data.length] = d;
55 | }
56 |
57 | var forecast = vis.stage()
58 | .selectAll('path.forecast')
59 | .data([data]);
60 |
61 | forecast.enter()
62 | .append('svg:path')
63 | .attr('d', drawLineGraph)
64 | .attr('class', 'forecast');
65 |
66 | forecast.exit().remove();
67 | })
68 | .add(vis,
69 | n3.annotation('line')
70 | .attr('id', 'lastLine')
71 | .start([600, 180])
72 | .end([600, 160])
73 | .style('stroke-width', 1)
74 | .style('stroke', 'grey'))
75 |
76 | .add(vis,
77 | n3.annotation('label')
78 | .attr('id', 'lastYearLbl')
79 | .html('Last year\'s forecast
')
80 | .pos([560, 125]))
81 |
82 | .add(vis,
83 | n3.annotation('line')
84 | .attr('id', 'latestLine')
85 | .start([600, 210])
86 | .end([600, 230])
87 | .style('stroke-width', 1)
88 | .style('stroke', 'grey'))
89 |
90 | .add(vis,
91 | n3.annotation('label')
92 | .attr('id', 'latestLbl')
93 | .html('Latest forecast
')
94 | .pos([565, 225]))
95 |
96 | n3.scene('scene_3')
97 | .subScene('scene_3a')
98 | .set(vis, 'year', 1980)
99 | .set(vis, 'plotForecasts', true)
100 | .set(vis, 'year', n3.util.iterate(1980, 1996, 1, 150))
101 |
102 | .add(vis,
103 | n3.annotation('highlightedPoint')
104 | .data([fullData[98]]),
105 | n3.trigger(vis)
106 | .where('year')
107 | .gte(1995))
108 |
109 | .add(vis,
110 | n3.annotation('line')
111 | .attr('id', 'line1995')
112 | .start([332.5, 145])
113 | .end([332.5, 195])
114 | .style('stroke-width', 1)
115 | .style('stroke', 'grey'),
116 | n3.trigger(vis)
117 | .where('year')
118 | .gte(1995))
119 |
120 | .add(vis, n3.annotation('label')
121 | .attr('id', 'lbl1995')
122 | .html('The 1995 forecast for 1999 did not predict a surplus...
')
123 | .pos([280, 195]),
124 | n3.trigger(vis)
125 | .where('year')
126 | .gte(1995))
127 |
128 | n3.scene('scene_3')
129 | .subScene('scene_3b')
130 | .set(vis, 'plotForecasts', true)
131 | .set(vis, 'year', n3.util.iterate(1995, 2009, 1, 150))
132 |
133 | .add(vis, n3.annotation('highlightedPoint')
134 | .data([fullData[98], fullData[204]]),
135 | n3.trigger(vis)
136 | .where('year')
137 | .gte(2008)
138 | )
139 |
140 | .add(vis, n3.annotation('line')
141 | .attr('id', 'line2008')
142 | .start([560, 92])
143 | .end([560, 142])
144 | .style('stroke-width', 1)
145 | .style('stroke', 'grey'),
146 |
147 | n3.trigger(vis)
148 | .where('year')
149 | .gte(2008)
150 | )
151 |
152 | .add(vis, n3.annotation('label')
153 | .attr('id', 'lbl2008')
154 | .html('... but the 2008 forecast for 2012 did.
')
155 | .pos([520, 142]),
156 |
157 | n3.trigger(vis)
158 | .where('year')
159 | .gte(2008)
160 | )
161 |
162 | n3.scene('scene_3')
163 | .subScene('scene_3c')
164 | .set(vis, 'year', 2008)
165 | .set(vis, 'plotForecasts', true)
166 | .set(vis, 'year', n3.util.iterate(2008, 2011, 1, 150))
167 |
168 | n3.timeline.transition('*', '*', function(fromScene, toScene) {
169 | $('#' + fromScene.sceneId).hide();
170 | $('#' + toScene.sceneId).show();
171 | });
172 |
173 | n3.timeline.transition(['scene_1', 'scene_2'],
174 | ['scene_3a', 'scene_3b', 'scene_3c', 'scene_4'],
175 | function(fromScene, toScene) { $('#slider').show(); })
176 |
177 | n3.timeline.transition(['scene_3a', 'scene_3b', 'scene_3c', 'scene_4'],
178 | ['scene_1', 'scene_2'],
179 | function(fromScene, toScene) { $('#slider').hide(); })
180 |
181 | n3.timeline.switchScene('scene_1');
--------------------------------------------------------------------------------
/examples/budgetForecast/vis.js:
--------------------------------------------------------------------------------
1 | var vis = n3.vis('budgetForecast')
2 | .data(fullData)
3 |
4 | .stage('#stage', 700, 400)
5 |
6 | .state('year', d3.range(1980, 2011))
7 | .state('plotForecasts', [true, false])
8 |
9 | .const('minYear', 1980)
10 | .const('maxYear', 2010)
11 | .const('maxYearForecast', 2020)
12 | .const('minValue', -1781)
13 | .const('maxValue', 519)
14 |
15 | .const('sx', function() {
16 | return d3.scale.linear()
17 | .domain([vis.const('minYear'), vis.const('maxYearForecast')])
18 | .range([0, vis.width()]);
19 | })
20 |
21 | .const('sy', function() {
22 | return d3.scale.linear()
23 | .domain([vis.const('minValue'), vis.const('maxValue')])
24 | .range([vis.height(), 0]);
25 | })
26 |
27 | .const('drawLineGraph', function() {
28 | return d3.svg.line()
29 | .x(function(d, i){ return vis.const('sx')()(d.forecastYear); })
30 | .y(function(d, i){ return vis.const('sy')()(d.value); });
31 | })
32 |
33 | .render(function() {
34 | // First draw zero line
35 | drawAxes(this);
36 |
37 | // Plot forecasts
38 | drawForecasts(this);
39 |
40 | // Plot actual budget figures
41 | drawActual(this);
42 | });
43 |
44 | function drawAxes(vis) {
45 | var sx = vis.const('sx')();
46 | var sy = vis.const('sy')();
47 |
48 | var formatNumber = function(nStr) {
49 | nStr += '';
50 | x = nStr.split('.');
51 | x1 = x[0];
52 | x2 = x.length > 1 ? '.' + x[1] : '';
53 | var rgx = /(\d+)(\d{3})/;
54 | while (rgx.test(x1)) {
55 | x1 = x1.replace(rgx, '$1' + '.' + '$2');
56 | }
57 |
58 | var newStr = x1 + x2;
59 | if(newStr.indexOf('-') != -1) {
60 | newStr = '-$' + newStr.substring(1);
61 | } else {
62 | newStr = '$' + newStr;
63 | }
64 |
65 | return newStr;
66 | }
67 |
68 | var xAxis = d3.range(vis.const('minYear'), vis.const('maxYearForecast'), 2);
69 | var yAxis = d3.range(vis.const('minValue'), vis.const('maxValue'), 200);
70 |
71 | vis.stage()
72 | .selectAll('line.xAxis')
73 | .data(xAxis)
74 | .enter()
75 | .append("svg:line")
76 | .attr("x1", function(d) { return sx(d); })
77 | .attr("y1", function() { return vis.height() + 20 })
78 | .attr("x2", function(d) { return sx(d); })
79 | .attr("y2", 0)
80 | .attr("stroke", "#fff")
81 | .attr("class", "xAxis");
82 |
83 | vis.stage()
84 | .selectAll("line.yAxis")
85 | .data(yAxis)
86 | .enter()
87 | .append("svg:line")
88 | .attr("x1", -20)
89 | .attr("y1", function(d) { return sy(d); })
90 | .attr("x2", function(d) { return vis.width() + 20 })
91 | .attr("y2", function(d) { return sy(d); })
92 | .attr("stroke", "#fff")
93 | .attr("class", "yAxis");
94 |
95 | vis.stage()
96 | .selectAll("text.xAxisLabels")
97 | .data(xAxis)
98 | .enter()
99 | .append("svg:text")
100 | .text(function(d) {
101 | if(d == vis.const('minYear') || d == vis.const('maxYearForecast'))
102 | return;
103 |
104 | var fullYear = d + '';
105 | return "'" + fullYear.substring(2);
106 | })
107 | .attr("x", function(d) { return sx(d); })
108 | .attr("dx", "10")
109 | .attr("y", function(d) { return sy(0); })
110 | .attr("dy", "-5")
111 | .attr("class", "xAxisLabels")
112 | .attr("fill", "#aaa")
113 | .attr("text-anchor", "end");
114 |
115 | vis.stage()
116 | .selectAll("text.yAxisLabels")
117 | .data(yAxis)
118 | .enter()
119 | .append("svg:text")
120 | .text(function(d) {
121 | if(d != 19 && d != vis.const('minValue'))
122 | return formatNumber(Math.round(d)) + ((Math.abs(d) > 1000) ? ' trillion' : ' billion');
123 | })
124 | .attr("x", 75)
125 | .attr("dx", function(d) { return Math.abs(d) > 1000 ? 15 : 0 })
126 | .attr("y", function(d) { return sy(d); })
127 | .attr("dy", "4")
128 | .attr("class", "yAxisLabels")
129 | .attr("fill", "#aaa")
130 | .attr("text-anchor", "end");
131 |
132 | var zeroData = [];
133 | for(var i = vis.const('minYear'); i <= vis.const('maxYearForecast'); i++)
134 | zeroData[zeroData.length] = {'budgetYear': i, 'forecastYear': i, 'value': 0};
135 |
136 | var path = vis.stage().selectAll('path#zero')
137 | .data([zeroData]);
138 |
139 | path.enter()
140 | .append('svg:path')
141 | .attr('id', 'zero')
142 | .attr('d', vis.const('drawLineGraph')());
143 | }
144 |
145 | function drawForecasts(vis) {
146 | var plot = vis.state('plotForecasts');
147 | var year = vis.state('year');
148 | var drawLineGraph = vis.const('drawLineGraph')();
149 | var dataTransform = vis.const('dataTransform');
150 | var fullData = vis.data();
151 |
152 | var data = [];
153 |
154 | if(plot == true) {
155 | var years = d3.range(vis.const('minYear'), vis.const('maxYear')+1);
156 | for(var i = 0; i < years.length; i++) {
157 | if(years[i] > year)
158 | break;
159 |
160 | var forecastData = [];
161 | for(var j = 0; j < fullData.length; j++) {
162 | if(fullData[j].budgetYear != years[i])
163 | continue;
164 |
165 | forecastData[forecastData.length] = fullData[j];
166 | }
167 |
168 | data[data.length] = forecastData;
169 | }
170 | }
171 |
172 | var forecast = vis.stage()
173 | .selectAll('path.forecast')
174 | .data(data);
175 |
176 | forecast.enter()
177 | .append('svg:path')
178 | .attr('d', drawLineGraph)
179 | .attr('class', 'forecast');
180 |
181 | forecast.transition()
182 | .attr('d', drawLineGraph)
183 |
184 | forecast.exit()
185 | .remove();
186 | }
187 |
188 | function drawActual(vis) {
189 | var year = vis.state('year');
190 | var drawLineGraph = vis.const('drawLineGraph')();
191 | var dataTransform = vis.const('dataTransform');
192 | var fullData = vis.data();
193 |
194 | var data = [];
195 |
196 | for(var i = 0; i < fullData.length; i++) {
197 | var d = fullData[i];
198 | if(d.budgetYear > year)
199 | continue;
200 |
201 | if(d.forecastYear != d.budgetYear - 1)
202 | continue;
203 |
204 | data[data.length] = d;
205 | }
206 |
207 | var actual = vis.stage().selectAll('path#actual')
208 | .data([data]);
209 |
210 | actual.enter()
211 | .append('svg:path')
212 | .attr('d', drawLineGraph)
213 | .attr('id', 'actual');
214 |
215 | actual.transition().attr('d', drawLineGraph);
216 |
217 | actual.exit().remove();
218 |
219 | // 2010 projection
220 | var projectedData = [];
221 | if(year >= 2010) {
222 | for(var i = 0; i < fullData.length; i++) {
223 | var d = fullData[i];
224 | if(d.budgetYear != 2010)
225 | continue;
226 |
227 | projectedData[projectedData.length] = d;
228 | }
229 | }
230 |
231 | var projected = vis.stage()
232 | .selectAll('path#projected')
233 | .data([projectedData]);
234 |
235 | projected.enter()
236 | .append('svg:path')
237 | .attr('d', drawLineGraph)
238 | .attr('id', 'projected');
239 |
240 | projected.transition().attr('d', drawLineGraph);
241 |
242 | projected.exit().remove();
243 | }
--------------------------------------------------------------------------------
/examples/habemusPapam/ellipsis.js:
--------------------------------------------------------------------------------
1 | var elVis = n3.vis('habemusPapam')
2 | .stage('#tableauViz', 1000, 475)
3 |
4 | .state('country', ['Afghanistan', 'Albania', 'Algeria', 'American Samoa', 'Andorra', 'Angola', 'Anguilla', 'Antigua and Barbuda', 'Argentina', 'Armenia', 'Aruba', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivia', 'Bosnia-Herzegovina', 'Botswana', 'Brazil', 'British Virgin Islands', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burma (Myanmar)', 'Burundi', 'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Cayman Islands', 'Central African Republic', 'Chad', 'Channel Islands', 'Chile', 'China', 'Colombia', 'Comoros', 'Cook Islands', 'Costa Rica', 'Croatia', 'Cuba', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'DRC', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Faeroe Islands', 'Falkland Islands', 'Fiji', 'Finland', 'France', 'French Guiana', 'French Polynesia', 'Gabon', 'Gambia', 'Georgia', 'Germany', 'Ghana', 'Gibraltar', 'Greece', 'Greenland', 'Grenada', 'Guadeloupe', 'Guam', 'Guatemala', 'Guinea', 'Guinea Bissau', 'Guyana', 'Haiti', 'Honduras', 'Hong Kong', 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran', 'Iraq', 'Ireland', 'Isle of Man', 'Israel', 'Italy', 'Ivory Coast', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kiribati', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Macau', 'Madagascar', 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta', 'Marshall Islands', 'Martinique', 'Mauritania', 'Mauritius', 'Mayotte', 'Mexico', 'Micronesia', 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Montserrat', 'Morocco', 'Mozambique', 'Namibia', 'Nauru', 'Nepal', 'Netherlands', 'Netherlands Antilles', 'New Caledonia', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'Niue', 'North Korea', 'Northern Mariana Islands', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Palestinian territories', 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru', 'Philippines', 'Poland', 'Portugal', 'Puerto Rico', 'Qatar', 'Republic of Macedonia', 'Republic of the Congo', 'Reunion', 'Romania', 'Russia', 'Rwanda', 'Samoa', 'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovakia', 'Slovenia', 'Solomon Islands', 'Somalia', 'South Africa', 'South Korea', 'South Sudan', 'Spain', 'Sri Lanka', 'St. Helena', 'St. Kitts and Nevis', 'St. Lucia', 'St. Pierre and Miquelon', 'St. Vincent and the Grenadines', 'Sudan', 'Suriname', 'Swaziland', 'Sweden', 'Switzerland', 'Syria', 'Taiwan', 'Tajikistan', 'Tanzania', 'Thailand', 'Timor-Leste', 'Togo', 'Tokelau', 'Tonga', 'Trinidad and Tobago', 'Tunisia', 'Turkey', 'Turkmenistan', 'Turks and Caicos', 'Tuvalu', 'U.S. Virgin Islands', 'Uganda', 'Ukraine', 'United Arab Emirates', 'United Kingdom', 'United States', 'Uruguay', 'Uzbekistan', 'Vanuatu', 'Vatican City', 'Venezuela', 'Vietnam', 'Wallis and Futuna', 'Western Sahara', 'Yemen', 'Zambia', 'Zimbabwe'])
5 | .render(function() {
6 | var countries = elVis.state('country').split(', ');
7 | if(countries.length == 1 && countries[0] == '')
8 | map.clearSelectedMarksAsync()
9 | else
10 | map.selectMarksAsync('Country', countries, tableauSoftware.SelectionUpdateType.REPLACE);
11 | });
12 |
13 |
14 | n3.scene('overview')
15 | .add(elVis,
16 | n3.annotation('label')
17 | .attr('id', 'cardinals')
18 | .attr('class', 'label')
19 | .html('The College of Cardinals ')
20 | .pos([327, 125]))
21 |
22 | .add(elVis,
23 | n3.annotation('label')
24 | .attr('id', 'pope')
25 | .attr('class', 'label')
26 | .html('Pope Francis ')
27 | .pos([150, 417]))
28 |
29 | n3.scene('overview').clone('cardinals')
30 | .set(elVis, 'country', '')
31 |
32 | .add(elVis,
33 | n3.annotation('label')
34 | .html("The College of Cardinals " +
35 | "115 cardinals participated in the 2013 Conclave. " +
36 | "However, most of them were from Europe. " +
37 | "This is in spite of the church's shifting demographics " +
38 | "(click for more info):
" +
39 | "" +
49 | "x
")
50 | .pos([702, 34])
51 | .attr('id', 'label_1364620620916')
52 | .attr('class', 'annotation')
53 | .style('width', '305px'))
54 |
55 | n3.scene('cardinals').clone('europe')
56 | .set('habemusPapam', 'country', 'Albania, Andorra, Armenia, Austria, Belarus, Belgium, Bosnia-Herzegovina, Bulgaria, Channel Islands, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Faeroe Islands, Finland, France, Georgia, Germany, Gibraltar, Greece, Greenland, Hungary, Iceland, Ireland, Isle of Man, Italy, Kosovo, Latvia, Liechtenstein, Lithuania, Luxembourg, Malta, Moldova, Monaco, Montenegro, Netherlands, Norway, Poland, Portugal, Republic of Macedonia, Romania, Russia, San Marino, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Ukraine, United Kingdom, Uzbekistan, Vatican City')
57 |
58 | n3.scene('cardinals').clone('asia')
59 | .set('habemusPapam', 'country', 'Afghanistan, Azerbaijan, Bahrain, Bangladesh, Bhutan, Brunei, Burma (Myanmar), Cambodia, China, Hong Kong, India, Indonesia, Iran, Iraq, Israel, Japan, Jordan, Kazakhstan, Kuwait, Kyrgyzstan, Laos, Lebanon, Macau, Malaysia, Maldives, Mongolia, Nepal, North Korea, Oman, Pakistan, Palestinian territories, Philippines, Qatar, Saudi Arabia, Singapore, South Korea, Sri Lanka, Syria, Taiwan, Tajikistan, Thailand, Timor-Leste, Turkey, Turkmenistan, United Arab Emirates, Vietnam, Yemen')
60 |
61 | n3.scene('cardinals').clone('africa')
62 | .set('habemusPapam', 'country', 'Algeria, Angola, Benin, Botswana, Burkina Faso, Burundi, Cameroon, Cape Verde, Central African Republic, Chad, Comoros, Djibouti, DRC, Egypt, Equatorial Guinea, Eritrea, Ethiopia, Gabon, Gambia, Ghana, Guinea, Guinea Bissau, Ivory Coast, Kenya, Lesotho, Liberia, Libya, Madagascar, Malawi, Mali, Mauritania, Mauritius, Mayotte, Morocco, Mozambique, Namibia, Niger, Nigeria, Republic of the Congo, Reunion, Rwanda, Sao Tome and Principe, Senegal, Seychelles, Sierra Leone, Somalia, South Africa, South Sudan, Sudan, Swaziland, Tanzania, Togo, Tunisia, Uganda, Western Sahara, Zambia, Zimbabwe')
63 |
64 | .add('habemusPapam',
65 | n3.annotation('label')
66 | .html('Catholicism’s growth in Africa has accelerated in recent decades. There was a groundswell after the '+
67 | 'Second Vatican Council of 1962-65, which authorised the use of vernacular at mass and delegated more power to locals.'+
68 | 'The church’s indigenisation proceeded. African song and dance were incorporated into services. Young African priests, '+
69 | 'not European missionaries, took charge.
' +
70 | 'More information at The Economist
' +
71 | "x
")
72 | .pos([702, 256])
73 | .attr('id', 'label_1364760621063')
74 | .attr('class', 'annotation')
75 | .style('width', '305px'))
76 |
77 | n3.scene('cardinals').clone('north_america')
78 | .set('habemusPapam', 'country', 'Canada, United States')
79 |
80 | n3.scene('cardinals').clone('latin_america')
81 | .set('habemusPapam', 'country', 'Anguilla, Antigua and Barbuda, Argentina, Aruba, Bahamas, Barbados, Belize, Bermuda, Bolivia, Brazil, British Virgin Islands, Cayman Islands, Chile, Colombia, Costa Rica, Cuba, Dominica, Dominican Republic, Ecuador, El Salvador, Falkland Islands, French Guiana, Grenada, Guadeloupe, Guatemala, Guyana, Haiti, Honduras, Jamaica, Martinique, Mexico, Montserrat, Netherlands Antilles, Nicaragua, Panama, Paraguay, Peru, Puerto Rico, St. Helena, St. Kitts and Nevis, St. Lucia, St. Pierre and Miquelon, St. Vincent and the Grenadines, Suriname, Trinidad and Tobago, Turks and Caicos, U.S. Virgin Islands, Uruguay, Venezuela')
82 |
83 | .add('habemusPapam',
84 | n3.annotation('label')
85 | .html('Although the Vatican had once seen the area as a “continent of hope,”' +
86 | " it now thought of it as a “continent of concern.”
" +
87 | "According to Brazil’s 2010 census, 65 percent of the population is Catholic, down from" +
88 | "over 90 percent in 1970. Similarly, between 2000 and 2010, the percentage of Mexicans that identify" +
89 | "as Catholic dropped from 88 to less than 83 -- the largest fall recorded to date. If these trends persist, " +
90 | 'by 2025 about 50 percent of all Latin Americans will be Catholic, down from approximately 70 percent today".
' +
91 | 'More information at Foreign Affairs
' +
92 | "x
")
93 | .pos([702, 256])
94 | .attr('id', 'label_1364760621063')
95 | .attr('class', 'annotation')
96 | .style('width', '305px'))
97 |
98 | n3.scene('cardinals').clone('oceania')
99 | .set('habemusPapam', 'country', 'American Samoa, Australia, Cook Islands, Fiji, French Polynesia, Guam, Kiribati, Marshall Islands, Micronesia, Nauru, New Caledonia, New Zealand, Niue, Northern Mariana Islands, Palau, Papua New Guinea, Samoa, Solomon Islands, Tokelau, Tonga, Tuvalu, Vanuatu, Wallis and Futuna')
100 |
101 | n3.scene('overview').clone('francis')
102 | .set(elVis, 'country', 'Argentina, Philippines, Hungary, Ghana, Sri Lanka, Brazil, Italy, Canada, Honduras, United States, Austria, Vatican')
103 |
104 | .add(elVis,
105 | n3.annotation('label')
106 | .html("Pope Francis " +
107 | "Perhaps the shift in the Catholic demographic weighed " +
108 | "on the cardinals? Pope Francis, formerly Cardinal " +
109 | "Bergoglio of Argentina, is the first non-European pope " +
110 | "in over 1,200 years, and the first Jesuit.
" +
111 | "Other reported frontrunners included:
" +
112 | "" +
126 | "x
")
127 | .pos([700, 8])
128 | .attr('id', 'label_1364624771223')
129 | .attr('class', 'annotation')
130 | .style('width', '275px'))
--------------------------------------------------------------------------------
/examples/habemusPapam/external-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/habemusPapam/external-link.png
--------------------------------------------------------------------------------
/examples/habemusPapam/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
82 |
83 |
84 |
85 |
86 |
109 |
110 | Habemus Papam!
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/examples/lib/colorbrewer/LICENSE:
--------------------------------------------------------------------------------
1 | Apache-Style Software License for ColorBrewer software and ColorBrewer Color
2 | Schemes
3 |
4 | Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State
5 | University.
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License"); you may not
8 | use this file except in compliance with the License. You may obtain a copy of
9 | the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 | License for the specific language governing permissions and limitations under
17 | the License.
18 |
19 | Redistribution and use in source and binary forms, with or without
20 | modification, are permitted provided that the following conditions are met:
21 |
22 | 1. Redistributions as source code must retain the above copyright notice, this
23 | list of conditions and the following disclaimer.
24 |
25 | 2. The end-user documentation included with the redistribution, if any, must
26 | include the following acknowledgment: "This product includes color
27 | specifications and designs developed by Cynthia Brewer
28 | (http://colorbrewer.org/)." Alternately, this acknowledgment may appear in the
29 | software itself, if and wherever such third-party acknowledgments normally
30 | appear.
31 |
32 | 4. The name "ColorBrewer" must not be used to endorse or promote products
33 | derived from this software without prior written permission. For written
34 | permission, please contact Cynthia Brewer at cbrewer@psu.edu.
35 |
36 | 5. Products derived from this software may not be called "ColorBrewer", nor
37 | may "ColorBrewer" appear in their name, without prior written permission of
38 | Cynthia Brewer.
39 |
--------------------------------------------------------------------------------
/examples/lib/d3.v2.js:
--------------------------------------------------------------------------------
1 | ../../node_modules/d3/d3.v2.js
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Paul Bakaus, http://jqueryui.com/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals (AUTHORS.txt, http://jqueryui.com/about) For exact
5 | contribution history, see the revision history and logs, available
6 | at http://jquery-ui.googlecode.com/svn/
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining
9 | a copy of this software and associated documentation files (the
10 | "Software"), to deal in the Software without restriction, including
11 | without limitation the rights to use, copy, modify, merge, publish,
12 | distribute, sublicense, and/or sell copies of the Software, and to
13 | permit persons to whom the Software is furnished to do so, subject to
14 | the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be
17 | included in all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_flat_0_aaaaaa_40x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_flat_75_ffffff_40x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_55_fbf9ee_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_75_dadada_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_75_e6e6e6_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_glass_95_fef1ec_1x400.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_highlight-soft_75_cccccc_1x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_2e83ff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_2e83ff_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_454545_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_454545_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_888888_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_888888_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_cd0a0a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_cd0a0a_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery-ui/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/examples/lib/jquery-ui/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/examples/lib/jquery/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 John Resig, http://jquery.com/
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/examples/lib/n3.js:
--------------------------------------------------------------------------------
1 | ../../n3.js
--------------------------------------------------------------------------------
/examples/unemployment/annualRates.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var width = 500;
3 | var height = 300;
4 |
5 | var minYear = 2004;
6 | var maxYear = 2011;
7 |
8 | var annualDataHash = {};
9 |
10 | var vis = n3.vis('annualRates')
11 | .stage('#annual_rates_stage', width, height)
12 |
13 | .state('year', d3.range(minYear, maxYear+1))
14 | .state('locationId', validLocationIds)
15 |
16 | .const('minYear', minYear)
17 | .const('maxYear', maxYear)
18 | .const('minRate', minRate)
19 | .const('maxRate', maxRate)
20 |
21 | .const('scales', getScales)
22 | .const('line', getLinePlotter)
23 |
24 | .render(function() {
25 | if(!vis.state('year') || !vis.state('locationId'))
26 | return;
27 |
28 | drawAxes(this);
29 |
30 | plotLines(this);
31 | });
32 |
33 | d3.select("#annual_rates")
34 | .append("svg")
35 | .attr('id', 'annual_rates_stage');
36 |
37 | var title = d3.select('#annual_rates')
38 | .append('p')
39 | .attr('id', 'annual_rates_title');
40 |
41 | d3.json("data/annualData.json", function(json) {
42 | parseData(json, 0, json.length);
43 | });
44 |
45 | // Data is extremely large, so process it in chunks of 100
46 | function parseData(json, offset, total) {
47 | var length = (total - offset > 100) ? offset + 100 : total;
48 | for(var i = offset; i < length; i++) {
49 | var d = json[i];
50 | annualDataHash[d.id] || (annualDataHash[d.id] = []);
51 |
52 | annualDataHash[d.id].push(d);
53 | }
54 | vis.data(annualDataHash);
55 | // console.log('done ' + i + ' ' + length + ' ' + offset);
56 | if(length != total)
57 | window.setTimeout(function() {
58 | parseData(json, (offset + 100), total)
59 | }, 100);
60 | }
61 |
62 | function minRate() {
63 | var natlData = annualDataHash['usa'];
64 | var locData = annualDataHash[vis.state('locationId')];
65 |
66 | var findMin = function(arr) {
67 | var min = Infinity;
68 | for(var i = 0; i < arr.length; i++)
69 | if(arr[i].rate < min)
70 | min = arr[i].rate;
71 |
72 | return min;
73 | }
74 |
75 | var minNatl = findMin(natlData);
76 | var minLoc = findMin(locData);
77 |
78 | return minNatl <= minLoc ? minNatl : minLoc;
79 | }
80 |
81 | function maxRate() {
82 | var natlData = annualDataHash['usa'];
83 | var locData = annualDataHash[vis.state('locationId')];
84 |
85 | var findMax = function(arr) {
86 | var max = -Infinity;
87 | for(var i = 0; i < arr.length; i++)
88 | if(arr[i].rate > max)
89 | max = arr[i].rate;
90 |
91 | return max;
92 | }
93 |
94 | var maxNatl = maxNatl = findMax(natlData);
95 | var maxLoc = maxLoc = findMax(locData);
96 |
97 | return maxNatl >= maxLoc ? maxNatl : maxLoc;
98 | }
99 |
100 | function getScales() {
101 | var sx = d3.scale.linear()
102 | .domain([minYear, maxYear])
103 | .range([0, width]);
104 |
105 | var sy = d3.scale.linear()
106 | .domain([minRate(), maxRate()])
107 | .range([height, 0]);
108 |
109 | return [sx, sy];
110 | }
111 |
112 | function getLinePlotter() {
113 | var scales = getScales();
114 | var sx = scales[0], sy = scales[1];
115 |
116 | var line = d3.svg.line()
117 | .x(function(d, i){ return sx(d.year); })
118 | .y(function(d, i){ return sy(d.rate); });
119 |
120 | return line;
121 | }
122 |
123 | function drawAxes(vis) {
124 | var xAxis = d3.range(minYear, maxYear+1);
125 | var yAxis = d3.range(Math.round(minRate()),
126 | Math.round(maxRate()));
127 | var scales = getScales();
128 | var sx = scales[0], sy = scales[1];
129 |
130 | var svg = vis.stage();
131 |
132 | var xGrid = svg.selectAll('line.xGrid')
133 | .data(xAxis);
134 |
135 | xGrid.enter().append("svg:line");
136 |
137 | xGrid.transition()
138 | .attr("x1", function(d) { return sx(d); })
139 | .attr("y1", function() { return height + 25 })
140 | .attr("x2", function(d) { return sx(d); })
141 | .attr("y2", 0)
142 | .attr("class", "xGrid");
143 |
144 | xGrid.exit().remove();
145 |
146 | var yGrid = svg.selectAll("line.yGrid")
147 | .data(yAxis);
148 |
149 | yGrid.enter().append("svg:line");
150 |
151 | yGrid.transition()
152 | .attr("x1", -10)
153 | .attr("y1", function(d) { return sy(d); })
154 | .attr("x2", function(d) { return width + 10 })
155 | .attr("y2", function(d) { return sy(d); })
156 | .attr("class", "yGrid");
157 |
158 | yGrid.exit().remove();
159 |
160 | var xLbls = svg.selectAll("text.xLbls")
161 | .data(xAxis);
162 |
163 | xLbls.enter().append("svg:text");
164 |
165 | xLbls.transition()
166 | .text(function(d) {
167 | return "'" + (d+'').substring(2);
168 | })
169 | .attr("x", function(d) { return sx(d); })
170 | .attr("dx", 10)
171 | .attr("y", function(d) { return height; })
172 | .attr("dy", 40)
173 | .attr("class", "xLbls")
174 | .attr("text-anchor", "end");
175 |
176 | xLbls.exit().remove();
177 |
178 | var yLbls = svg.selectAll("text.yLbls")
179 | .data(yAxis);
180 |
181 | yLbls.enter().append("svg:text");
182 |
183 | yLbls.transition()
184 | .text(function(d) {
185 | return d % 2 == 0 ? d + '%' : '';
186 | })
187 | .attr("x", -15)
188 | .attr("y", function(d) { return sy(d); })
189 | .attr("dy", "4")
190 | .attr("class", "yLbls")
191 | .attr("text-anchor", "end");
192 |
193 | yLbls.exit().remove();
194 | }
195 |
196 | function plotLines(vis) {
197 | var svg = vis.stage();
198 | var scales = getScales();
199 | var sx = scales[0], sy = scales[1];
200 | var line = getLinePlotter();
201 | var data = [[], []];
202 | var natlData = annualDataHash['usa'];
203 | var locData = annualDataHash[vis.state('locationId')];
204 |
205 | for(var i = 0; i < natlData.length; i++)
206 | if(natlData[i].year <= vis.state('year'))
207 | data[0].push(natlData[i]);
208 |
209 | for(var i = 0; i < locData.length; i++)
210 | if(locData[i].year <= vis.state('year'))
211 | data[1].push(locData[i]);
212 |
213 | var p = svg.selectAll('path')
214 | .data(data, function(d) { return d.id; });
215 |
216 | p.enter().append('svg:path');
217 |
218 | p.transition()
219 | .attr('id', function(d) { return d.length > 0 ? d[0].id : ''; })
220 | .attr('d', line);
221 |
222 | p.exit().remove();
223 |
224 | if(data[1].length > 0)
225 | title.html('National Unemployment Rates vs ' +
226 | '' + data[1][0]['name'] + ' ');
227 | }
228 | }).call(this);
--------------------------------------------------------------------------------
/examples/unemployment/choropleth.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var zoomExtent = [1, 15];
3 | var width = 960;
4 | var height = 500;
5 | var path = d3.geo.path();
6 |
7 | var statesUnemployment, countiesUnemployment; // Loaded async
8 |
9 | var vis = n3.vis('choropleth')
10 | .data({})
11 | .stage('#choropleth_stage g', width, height)
12 |
13 | .state('zoom', zoomExtent, true)
14 | .bind('zoom', function(val) {
15 | $( "#zoom_slider" ).slider('value', val);
16 | })
17 |
18 | .state('translateX', [-Infinity, Infinity], true)
19 | .state('translateY', [-Infinity, Infinity], true)
20 |
21 | .const('zoomExtent', zoomExtent)
22 | .const('path', path)
23 | .const('quantize', quantize)
24 |
25 | .render(redraw);
26 |
27 | // Slider is part of visualization, not story!
28 | $("#zoom_slider").slider({
29 | orientation: "vertical",
30 | min: zoomExtent[0],
31 | max: zoomExtent[1],
32 | value: 1,
33 | step: 0.5,
34 | start: function(event, ui) {
35 | $(this).slider('option', 'oldVal', ui.value);
36 | },
37 | slide: function( event, ui ) {
38 | var oldVal = $(this).slider('option', 'oldVal');
39 | var newVal = ui.value;
40 | $(this).slider('option', 'oldVal', ui.value);
41 |
42 | fireZoomEvent(oldVal, newVal);
43 | }
44 | });
45 |
46 | function fireZoomEvent(oldVal, newVal) {
47 | // void initWebKitWheelEvent(int wheelDeltaX, int wheelDeltaY, DOMWindow
48 | // view, int screenX, int screenY, int clientX, int clientY, bool ctrlKey,
49 | // bool altKey, bool shiftKey, bool metaKey);
50 |
51 | var diff = newVal - oldVal;
52 | var wheelDeltaY = Math.pow(1, Math.abs(diff));
53 | wheelDeltaY *= (newVal < oldVal) ? -1 : 1;
54 |
55 | var evt = document.createEvent("WheelEvent");
56 | evt.initWebKitWheelEvent(0, wheelDeltaY, window,
57 | width/2, height/2, width/2, height/2,
58 | false, false, false, false);
59 |
60 | document.getElementById('choropleth_stage').dispatchEvent(evt);
61 | }
62 |
63 | // Slightly modified version of D3 Choropleth examples
64 | // Capped the zoom extents and have counties appear at
65 | // a certain zoom level.
66 | var svg = d3.select("#choropleth")
67 | .append("svg")
68 | .attr('id', 'choropleth_stage')
69 | .call(d3.behavior.zoom().scaleExtent(zoomExtent)
70 | .on("zoom", onZoom))
71 | .append("g");
72 |
73 | var counties = svg.append("g")
74 | .attr("id", "counties")
75 | .attr("class", "Blues");
76 |
77 | var states = svg.append("g")
78 | .attr("id", "states")
79 | .attr("class", "Blues");
80 |
81 | d3.json("data/states-unemployment.json", function(json) {
82 | statesUnemployment = json;
83 | })
84 |
85 | d3.json("data/us-states.json", function(json) {
86 | var visData = vis.data();
87 | visData['states'] = json;
88 |
89 | states.selectAll("path")
90 | .data(json.features)
91 | .enter().append("path")
92 | .attr("class", function(d) {
93 | return quantize(true, d);
94 | })
95 | .attr("d", path);
96 | });
97 |
98 | d3.json("data/counties-unemployment.json", function(json) {
99 | countiesUnemployment = json;
100 | })
101 |
102 | d3.json("data/us-counties.json", function(json) {
103 | var visData = vis.data();
104 | visData['counties'] = json;
105 |
106 | counties.selectAll("path")
107 | .data(json.features)
108 | .enter().append("path")
109 | .attr("class", function(d) {
110 | return quantize(false, d);
111 | })
112 | .attr("d", path);
113 | });
114 |
115 | function quantize(s, d) {
116 | var val = s ? statesUnemployment[d.id] : countiesUnemployment[d.id];
117 | return "q" + Math.min(8, ~~(val * 9 / 12)) + "-9";
118 | }
119 |
120 | function onZoom() {
121 | vis.state('zoom', d3.event.scale);
122 | vis.state('translateX', d3.event.translate[0]);
123 | vis.state('translateY', d3.event.translate[1]);
124 | }
125 |
126 | function redraw() {
127 | svg.attr("transform", "translate(" +
128 | (vis.state('translateX') || 0) + "," +
129 | (vis.state('translateY') || 0) + ")" +
130 | "scale(" + vis.state('zoom') + ")");
131 |
132 | // If we're at zoom level > 2, show counties by making states
133 | // transparent
134 | states.selectAll('path')
135 | .style('fill', vis.state('zoom') >= 2 ? 'none' : null);
136 | }
137 | }).call(this);
138 |
--------------------------------------------------------------------------------
/examples/unemployment/data/states-unemployment.json:
--------------------------------------------------------------------------------
1 | {
2 | "01": 9.0,
3 | "02": 7.6,
4 | "04": 9.5,
5 | "05": 8.0,
6 | "06": 11.7,
7 | "08": 8.3,
8 | "09": 8.8,
9 | "10": 7.3,
10 | "11": 10.2,
11 | "12": 10.5,
12 | "13": 9.8,
13 | "15": 6.7,
14 | "16": 8.7,
15 | "17": 9.8,
16 | "18": 9.0,
17 | "19": 5.9,
18 | "20": 6.7,
19 | "21": 9.5,
20 | "22": 7.3,
21 | "23": 7.5,
22 | "24": 7.0,
23 | "25": 7.4,
24 | "26": 10.3,
25 | "27": 6.4,
26 | "28": 10.7,
27 | "29": 8.6,
28 | "30": 6.8,
29 | "31": 4.4,
30 | "32": 13.5,
31 | "33": 5.4,
32 | "34": 9.3,
33 | "35": 7.4,
34 | "36": 8.2,
35 | "37": 10.5,
36 | "38": 3.5,
37 | "39": 8.6,
38 | "40": 6.2,
39 | "41": 9.5,
40 | "42": 7.9,
41 | "44": 11.3,
42 | "45": 10.3,
43 | "46": 4.7,
44 | "47": 9.2,
45 | "48": 7.9,
46 | "49": 6.7,
47 | "50": 5.6,
48 | "51": 6.2,
49 | "53": 9.2,
50 | "54": 8.0,
51 | "55": 7.5,
52 | "56": 6.0,
53 | "72": 15.7
54 | }
--------------------------------------------------------------------------------
/examples/unemployment/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | U.S. Unemployment by County
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/unemployment/unemployment.css:
--------------------------------------------------------------------------------
1 | @import url("../lib/jquery-ui/jquery-ui.css");
2 |
3 | body {
4 | font-family: Verdana, sans-serif;
5 | font-size: 12px;
6 | }
7 |
8 | #choropleth svg {
9 | background: #eee;
10 | width: 960px;
11 | height: 500px;
12 | }
13 |
14 | #annual_rates svg {
15 | background: #fff;
16 | width: 500px;
17 | height: 300px;
18 | border: 3px solid orange;
19 | padding: 10px 20px 50px 50px;
20 | }
21 |
22 | #counties path {
23 | stroke: #fff;
24 | stroke-width: .25px;
25 | }
26 |
27 | #states path {
28 | stroke: #fff;
29 | stroke-width: 1.5px;
30 | }
31 |
32 | #choropleth circle {
33 | fill: orange;
34 | cursor: pointer;
35 | }
36 |
37 | #choropleth line.annotation {
38 | stroke: orange;
39 | stroke-width: 3px;
40 | }
41 |
42 | #annual_rates path {
43 | stroke: forestgreen;
44 | stroke-width: 5px;
45 | fill: none;
46 | }
47 |
48 | path#usa { stroke: steelblue !important; }
49 |
50 | #annual_rates line.xGrid, #annual_rates line.yGrid {
51 | stroke: #eee;
52 | stroke-width: 1px;
53 | shape-rendering: crispEdges;
54 | }
55 |
56 | #annual_rates line.annotation {
57 | stroke: black;
58 | stroke-width: 1px;
59 | }
60 |
61 | #annual_rates text.xLbls, #annual_rates text.yLbls {
62 | fill: #ccc;
63 | }
64 |
65 | #annual_rates div.annotation {
66 | background: #fff;
67 | padding: 7px;
68 | }
69 |
70 | #annual_rates div.annotation a {
71 | background: #ddd;
72 | padding: 0 3px 3px 3px;
73 | font-weight: bold;
74 | text-decoration: none;
75 | color: #000;
76 | }
77 |
78 | #annual_rates div.annotation a:hover { background: #eee; }
79 |
80 | #annual_rates_title {
81 | position: absolute;
82 | top: 5px;
83 | left: 60px;
84 | width: 225px;
85 | background: #fff;
86 | font-weight: bold;
87 | }
88 |
89 | #annual_rates_title span.usa { color: steelblue; }
90 | #annual_rates_title span.location { color: forestgreen; }
91 |
92 | #zoom_slider {
93 | float: left;
94 | margin-right: 20px;
95 | height: 150px;
96 | }
97 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "n3",
3 | "version": "0.9.0",
4 | "description": "A small, free JavaScript library for telling stories through visualizations.",
5 | "keywords": [
6 | "visualization",
7 | "story",
8 | "storytelling",
9 | "narrative"
10 | ],
11 | "author": "Arvind Satyanarayan (http://arvindsatya.com/)",
12 | "repository": {
13 | "type": "git",
14 | "url": "http://github.com/StanfordHCI/s3.git"
15 | },
16 | "main": "n3.js",
17 | "dependencies": {
18 | "d3": "2.8.x"
19 | },
20 | "devDependencies": {
21 | "uglify-js": "1.2.3",
22 | "coffee-script": "1.2.x",
23 | "jasmine-node": "1.0.x"
24 | },
25 | "scripts": {
26 | "build": "cake build",
27 | "test": "cake test"
28 | }
29 | }
--------------------------------------------------------------------------------
/src/annotation.coffee:
--------------------------------------------------------------------------------
1 | class N3Annotation
2 | @types =
3 | circle:
4 | enterFn: (r, [cx, cy]) ->
5 | selector = n3.util.getSelector('circle', @attrs)
6 | stage = if @vis()? then @vis().stage() else d3
7 |
8 | c = stage.selectAll(selector)
9 | .data(if @data()? then @data() else [0])
10 |
11 | c.enter()
12 | .append('svg:circle')
13 | .attr('r', r)
14 | .attr('cx', cx)
15 | .attr('cy', cy)
16 |
17 | c.transition()
18 | .attr('r', r)
19 | .attr('cx', cx)
20 | .attr('cy', cy)
21 |
22 | @applyAttrs c
23 | @applyStyles c
24 |
25 | true
26 |
27 | exitFn: (r, [cx, cy]) ->
28 | selector = n3.util.getSelector('circle', @attrs)
29 | stage = if @vis()? then @vis().stage() else d3
30 |
31 | stage.selectAll(selector).remove()
32 |
33 | true
34 |
35 | ellipse:
36 | enterFn: ([rx, ry], [cx, cy]) ->
37 | selector = n3.util.getSelector('ellipse', @attrs)
38 | stage = if @vis()? then @vis().stage() else d3
39 |
40 | e = stage.selectAll(selector)
41 | .data(if @data()? then @data() else [0])
42 |
43 | e.enter()
44 | .append('svg:ellipse')
45 | .attr('rx', rx)
46 | .attr('ry', ry)
47 | .attr('cx', cx)
48 | .attr('cy', cy)
49 |
50 | e.transition()
51 | .attr('rx', rx)
52 | .attr('ry', ry)
53 | .attr('cx', cx)
54 | .attr('cy', cy)
55 |
56 | @applyAttrs e
57 | @applyStyles e
58 |
59 | true
60 |
61 | exitFn: ([rx, ry], [cx, cy]) ->
62 | selector = n3.util.getSelector('ellipse', @attrs)
63 | stage = if @vis()? then @vis().stage() else d3
64 |
65 | stage.selectAll(selector).remove()
66 |
67 | true
68 |
69 | line:
70 | enterFn: ([x1, y1], arrow1, [x2, y2], arrow2) ->
71 | # TODO: add arrowheads
72 | selector = n3.util.getSelector('line', @attrs)
73 | stage = if @vis()? then @vis().stage() else d3
74 |
75 | l = stage.selectAll(selector)
76 | .data(if @data()? then @data() else [0])
77 |
78 | l.enter()
79 | .append('svg:line')
80 | .attr('x1', x1)
81 | .attr('y1', y1)
82 | .attr('x2', x2)
83 | .attr('y2', y2)
84 |
85 | l.transition()
86 | .attr('x1', x1)
87 | .attr('y1', y1)
88 | .attr('x2', x2)
89 | .attr('y2', y2)
90 |
91 | @applyAttrs l
92 | @applyStyles l
93 |
94 | true
95 |
96 | exitFn: ([x1, y1], arrow1, [x2, y2], arrow2) ->
97 | selector = n3.util.getSelector('line', @attrs)
98 | stage = if @vis()? then @vis().stage() else d3
99 |
100 | stage.selectAll(selector).remove()
101 |
102 | true
103 |
104 | rectangle:
105 | enterFn: ([w, h], [x, y]) ->
106 | selector = n3.util.getSelector('rect', @attrs)
107 | stage = if @vis()? then @vis().stage() else d3
108 |
109 | r = stage.selectAll(selector)
110 | .data(if @data()? then @data() else [0])
111 |
112 | r.enter()
113 | .append('svg:rect')
114 | .attr('x', x)
115 | .attr('y', y)
116 | .attr('width', w)
117 | .attr('height', h)
118 |
119 | r.transition()
120 | .attr('x', x)
121 | .attr('y', y)
122 | .attr('width', w)
123 | .attr('height', h)
124 |
125 | @applyAttrs r
126 | @applyStyles r
127 |
128 | true
129 |
130 | exitFn: ([w, h], [x, y]) ->
131 | selector = n3.util.getSelector('rect', @attrs)
132 | stage = if @vis()? then @vis().stage() else d3
133 |
134 | stage.selectAll(selector).remove()
135 |
136 | true
137 |
138 | label:
139 | enterFn: (text, html, [x, y]) ->
140 | selector = n3.util.getSelector('div', @attrs)
141 | stage = if @vis()? then @vis().stage() else d3
142 |
143 | # position the div absolutely
144 | @styles['position'] = 'absolute'
145 | @styles['left'] = (stage.property('offsetLeft') + x) + 'px'
146 | @styles['top'] = (stage.property('offsetTop') + y) + 'px'
147 |
148 | d = d3.select(stage[0][0].parentNode).selectAll(selector)
149 | .data(if @data()? then @data() else [0])
150 |
151 | d.enter()
152 | .append('div')
153 | .text(text)
154 | .html(html)
155 |
156 | @applyAttrs d
157 | @applyStyles d
158 |
159 | true
160 |
161 | exitFn: (text, html, [x, y]) ->
162 | selector = n3.util.getSelector('div', @attrs)
163 | stage = if @vis()? then @vis().stage() else d3
164 |
165 | d3.selectAll(selector).remove()
166 |
167 | true
168 |
169 | constructor: (@type) ->
170 | @enterFn = N3Annotation.types[@type]?.enterFn
171 | @exitFn = N3Annotation.types[@type]?.exitFn
172 |
173 | @annotId = @type + "" + new Date().getTime()
174 | @autoExitFlag = true
175 | @arguments = []
176 | @attrs = {}
177 | @styles = {}
178 |
179 | return this
180 |
181 | enter: (@enterFn) ->
182 | N3Annotation.types[@type] or= {}
183 | N3Annotation.types[@type].enterFn = enterFn
184 |
185 | return this
186 |
187 | exit: (@exitFn) ->
188 | N3Annotation.types[@type] or= {}
189 | N3Annotation.types[@type].exitFn = exitFn
190 |
191 | return this
192 |
193 | autoExit: (@autoExitFlag) ->
194 | return this
195 |
196 | data: (data) ->
197 | if arguments.length == 1
198 | @dataObj = data
199 |
200 | return this
201 | else
202 | return if typeof @dataObj == 'function' then @dataObj() else @dataObj
203 |
204 | vis: (vis) ->
205 | if arguments.length == 1
206 | vis = vis.visId if typeof vis == 'object'
207 | @visId = vis
208 |
209 | return this
210 | else
211 | N3Vis.lookup[@visId]
212 |
213 | add: ->
214 | @enterFn @arguments...
215 |
216 | remove: ->
217 | @exitFn @arguments...
218 |
219 | args: (@arguments...) ->
220 | return this
221 |
222 | attr: (key, value) ->
223 | if arguments.length == 2
224 | @attrs[key] = value
225 |
226 | return this
227 | else
228 | @attrs[key]
229 |
230 | applyAttrs: (selection) ->
231 | true unless selection?
232 | selection.attr(key, value) for key, value of @attrs
233 | true
234 |
235 | style: (key, value) ->
236 | if arguments.length == 2
237 | @styles[key] = value
238 |
239 | return this
240 | else
241 | @styles[key]
242 |
243 | applyStyles: (selection) ->
244 | true unless selection?
245 | selection.style(key, value) for key, value of @styles
246 | true
247 |
248 | # For built in types, expose arguments as methods. These are only setters.
249 | radius: (r) ->
250 | throw 'not an ellipse/circle' unless \
251 | @type == 'circle' or @type == 'ellipse'
252 |
253 | @arguments[0] = r
254 |
255 | return this
256 |
257 | center: ([cx, cy]) ->
258 | throw 'not an ellipse/circle' unless \
259 | @type == 'circle' or @type == 'ellipse'
260 |
261 | @arguments[1] = [cx, cy]
262 |
263 | return this
264 |
265 | start: ([x, y], arrow) ->
266 | throw 'not a line' unless @type == 'line'
267 |
268 | @arguments[0] = [x, y]
269 | @arguments[1] = arrow
270 |
271 | return this
272 |
273 | end: ([x, y], arrow) ->
274 | throw 'not a line' unless @type == 'line'
275 |
276 | @arguments[2] = [x, y]
277 | @arguments[3] = arrow
278 |
279 | return this
280 |
281 | size: ([x, y]) ->
282 | throw 'not a rectangle' unless @type == 'rectangle'
283 |
284 | @arguments[0] = [x, y]
285 |
286 | return this
287 |
288 | pos: ([x, y]) ->
289 | throw 'not a label/rectangle' unless \
290 | @type == 'rectangle' or @type == 'label'
291 |
292 | @arguments[if @type == 'rectangle' then 1 else 2] = [x, y]
293 |
294 | return this
295 |
296 | text: (str) ->
297 | throw 'not a label' unless @type == 'label'
298 |
299 | @arguments[0] = str
300 |
301 | return this
302 |
303 | html: (html) ->
304 | throw 'not a label' unless @type == 'label'
305 |
306 | @arguments[1] = html
307 |
308 | return this
309 |
310 | n3.annotation = (typeId) ->
311 | new N3Annotation(typeId)
312 |
313 | n3.annotation.def = (typeId) ->
314 | new N3Annotation(typeId)
--------------------------------------------------------------------------------
/src/scene.coffee:
--------------------------------------------------------------------------------
1 | class N3Scene
2 | @scenes = {}
3 |
4 | constructor: (@sceneId) ->
5 | # members = [
6 | # {
7 | # visId: visId,
8 | # state: {
9 | # id: stateId
10 | # value: value
11 | # },
12 | # member: annotation || function
13 | # trigger: triggerObj
14 | #
15 | # }
16 | # ]
17 | @members = []
18 | @subScenes =
19 | order: ''
20 |
21 | return this
22 |
23 | set: (vis, stateId, val, triggerObj) ->
24 | vis = vis.visId if typeof vis == 'object'
25 |
26 | member =
27 | visId: vis
28 | state:
29 | id: stateId
30 | value: val
31 | trigger: triggerObj
32 |
33 | @members.push member
34 |
35 | return this
36 |
37 | add: (vis, memberObj, triggerObj) ->
38 | vis = vis.visId if typeof vis == 'object'
39 |
40 | member =
41 | visId: vis
42 | member: memberObj
43 | trigger: triggerObj
44 |
45 | @members.push member
46 |
47 | return this
48 |
49 | # 1-index
50 | member: (memberIndex) ->
51 | return @members[memberIndex + 1]?.member
52 |
53 | clone: (sceneID) ->
54 | newScene = n3.scene(sceneID)
55 | newScene.members = n3.util.clone @members
56 | newScene.subScenes = n3.util.clone @subScenes
57 |
58 | return newScene
59 |
60 | subScene: (subSceneId) ->
61 | if @subScenes[subSceneId]?
62 | return @subScenes[subSceneId]
63 | else
64 | subScene = new N3Scene(subSceneId)
65 | subScene.parent = this
66 |
67 | @subScenes[subSceneId] = subScene
68 |
69 | return subScene
70 |
71 | evalMember: (memberIndex) ->
72 | m = @members[memberIndex]
73 | return true unless m?
74 |
75 | vis = N3Vis.lookup[m.visId]
76 |
77 | if m.state?
78 | val = m.state.value
79 |
80 | # To allow for some fun, allow states to be set my a function. If the fn returns
81 | # false, assume that it'll be setting the state itself.
82 | if typeof val == 'function'
83 | val = val(vis, m.state.id)
84 | vis?.state(m.state.id, val) unless val == false
85 | else
86 | vis?.state(m.state.id, m.state.value)
87 | else
88 | if typeof m.member == 'function'
89 | m.member(vis) # call the function, pass vis as arg
90 | else if m.member?.annotId? # check for N3Annotation
91 | m.member.vis(m.visId)
92 | m.member.add()
93 |
94 | N3Trigger.notify(N3Trigger.TYPES.DELAY, N3Trigger.WHERE.DELAY + memberIndex, 1)
95 |
96 | true
97 |
98 | n3.scene = (sceneId) ->
99 | N3Scene.scenes[sceneId] or= new N3Scene(sceneId)
--------------------------------------------------------------------------------
/src/state.coffee:
--------------------------------------------------------------------------------
1 | class N3State
2 | constructor: (@visId, @stateId, @validValues, @continuous) ->
3 | @bindings = []
4 |
5 | vis: ->
6 | N3Vis.lookup[@visId]
7 |
8 | get: ->
9 | @val
10 |
11 | set: (val) ->
12 | @prevVal = @val
13 | valid = if @continuous then (val >= @validValues[0] && val <= @validValues[1]) \
14 | else (@validValues.indexOf(val) != -1)
15 |
16 | # throw "#{val} not in the list of valid values: #{@validValues}" \
17 | # unless valid
18 |
19 | @val = val
20 |
21 | @notify()
22 |
23 | bind: (funcPtr) ->
24 | @bindings.push funcPtr
25 |
26 | notify: ->
27 | @vis()?.renderFn?();
28 | N3Trigger.notify(N3Trigger.TYPES.VIS, [@visId, @stateId], @val)
29 |
30 | binding.call(@vis(), @val) for binding in @bindings
--------------------------------------------------------------------------------
/src/timeline.coffee:
--------------------------------------------------------------------------------
1 | class N3Timeline
2 | @triggers = {}
3 | @deferredTriggers = {}
4 | @transitions = {}
5 | @startTime = 0
6 | @elapsedTime = 0
7 | @paused = false
8 |
9 | @switchScene: (sceneId) ->
10 | @prevSceneId = @currSceneId
11 | @prevParentId = @currParentId
12 | prevScene = if @prevParentId? then \
13 | N3Scene.scenes[@prevParentId].subScenes[@prevSceneId] else \
14 | N3Scene.scenes[@prevSceneId]
15 |
16 | if sceneId.indexOf('>') != -1 # switching to subscene
17 | @currParentId = sceneId.split('>')[0].trim()
18 | currParent = N3Scene.scenes[@currParentId]
19 | @currSceneId = sceneId.split('>')[1].trim()
20 | currentScene = currParent.subScenes[@currSceneId]
21 | else
22 | @currParentId = undefined
23 | currParent = undefined
24 | @currSceneId = sceneId
25 | currentScene = N3Scene.scenes[@currSceneId]
26 |
27 | # We want to remove annotations only if prevScene and currentScene
28 | # aren't subscenes of the same parent scene
29 | if prevScene?
30 | unless prevScene.parent? and currentScene.parent? and \
31 | prevScene.parent.sceneId == currentScene.parent.sceneId
32 |
33 | members = []
34 | members.push m for m in prevScene.members
35 | if prevScene.parent?
36 | for subSceneId, subScene of prevScene.parent.subScenes
37 | continue unless subScene.members?
38 | members.push m for m in subScene.members
39 |
40 | for m in members
41 | @deregisterTrigger m.trigger
42 |
43 | continue if m.state?
44 | continue unless m.member?.annotId? # check for N3Annotation
45 |
46 | m.member.vis(m.visId) # just in case
47 | m.member.remove() if m.member.autoExitFlag
48 |
49 | # Run any transitions
50 | if @transitions[@prevSceneId]?[@currSceneId]?
51 | for transFunc in @transitions[@prevSceneId][@currSceneId]
52 | transFunc(prevScene, currentScene)
53 |
54 | # TODO: TRANSITIONS for Parents/Subscenes
55 |
56 | # if prevParent? or currParent? # Transition parsing for subscenes
57 | #
58 | #
59 | #
60 | # if @transitions[@prevSceneId]?[currParentId]? # Transitions for parent scenes
61 | # for transFunc in @transitions[@prevSceneId][currParentId]
62 | # transFunc(prevScene, currParent)
63 | #
64 | # if @transitions[@prevSceneId]?[sceneId]? # Transitions defined for parent > child
65 | # for transFunc in @transitions[@prevSceneId][sceneId]
66 | # transFunc(prevScene, currentScene)
67 |
68 | # Start the timer for the current scene after the transition is complete
69 | @start(true)
70 |
71 | evaluateMembers = [];
72 |
73 | if currentScene?
74 | for m, i in currentScene.members
75 | evaluateMembers[i] = false;
76 |
77 | if m.trigger?
78 | # If we see a trigger, feed it ambient values, to see
79 | # if the trigger conditions have already been met. If it has,
80 | # evaluate the member. If not, register the trigger and skip
81 | # evaluation.
82 | # ACTUALLY -- since we register triggers first, don't check ambience.
83 | # currentValue = null
84 | #
85 | # if m.trigger.type == N3Trigger.TYPES.VIS
86 | # visId = m.trigger.test[0]
87 | # stateId = m.trigger.test[1]
88 | #
89 | # currentValue = N3Vis.lookup[visId]?.state(stateId)
90 | #
91 | # if m.trigger.type == N3Trigger.TYPES.DOM or \
92 | # m.trigger.type == N3Trigger.TYPES.DELAY or \
93 | # m.trigger.evaluate(m.trigger.test, currentValue) == false
94 |
95 | @registerTrigger(m.trigger, i)
96 | continue
97 |
98 | evaluateMembers[i] = true;
99 |
100 | # In case the first member has a delay trigger
101 | N3Trigger.notify(N3Trigger.TYPES.DELAY, N3Trigger.WHERE.DELAY + '-1', 1)
102 |
103 | for m, i in currentScene.members
104 | currentScene.evalMember(i) if evaluateMembers[i]
105 |
106 | # Now that all members have been added, see if we can register
107 | # some of our defered triggers.
108 | for id, t of @deferredTriggers
109 | @registerTrigger(t.trigger, t.memberIndex)
110 |
111 | true
112 |
113 | @registerTrigger: (trigger, memberIndex) ->
114 | return true unless trigger?
115 |
116 | bindDelay = (trigger) ->
117 | # If it's a delay trigger, automatically bind it to the prev
118 | # member's index
119 | if trigger.type == N3Trigger.TYPES.DELAY
120 | trigger.where(N3Trigger.WHERE.DELAY + (memberIndex - 1))
121 |
122 | # For OR or AND triggers, recursively apply this.
123 | if trigger.triggers?
124 | trigger.triggers = (bindDelay(t) for t in trigger.triggers)
125 |
126 | return trigger
127 |
128 | trigger = bindDelay(trigger);
129 |
130 | @triggers[trigger.triggerId] =
131 | sceneId: @currSceneId
132 | parentId: @currParentId
133 | memberIndex: memberIndex
134 |
135 | success = N3Trigger.register(trigger)
136 | if success
137 | delete @deferredTriggers[trigger.triggerId]
138 | else
139 | @deferredTriggers[trigger.triggerId] =
140 | trigger: trigger
141 | memberIndex: memberIndex
142 |
143 | true
144 |
145 | @deregisterTrigger: (trigger) ->
146 | return true unless @triggers[trigger?.triggerId]?
147 |
148 | delete @triggers[trigger.triggerId]
149 | delete @deferredTriggers[trigger.triggerId]
150 | N3Trigger.deregister(trigger)
151 |
152 | true
153 |
154 | @notifyTrigger: (trigger, evaluated) ->
155 | if @triggers[trigger.triggerId]?
156 | t = @triggers[trigger.triggerId]
157 |
158 | if t['eval'] == evaluated # If the trigger has already been evaluated
159 | return; # to this value, do nothing
160 |
161 | scene = if t.parentId? then \
162 | N3Scene.scenes[t.parentId].subScenes[t.sceneId] \
163 | else N3Scene.scenes[t.sceneId]
164 |
165 | if evaluated == true
166 | if t.memberIndex? # Member triggers
167 | scene?.evalMember(t.memberIndex)
168 | # else # Scene triggers
169 | # if t.parentId? then @switchScenes(t.parentId + '>' + t.sceneId) else @switchScenes(t.sceneId)
170 | else
171 | m = if t.memberIndex? then scene.members[t.memberIndex] else null
172 | if m?.member?.annotId?
173 | m.member.vis(m.visId) # just in case
174 | m?.member.remove()
175 |
176 | # See if this trigger has caused some member to be added such that
177 | # we can now register some of our defered triggers.
178 | for id, t of @deferredTriggers
179 | @registerTrigger(t.trigger, t.memberIndex)
180 |
181 | @triggers[trigger.triggerId]['eval'] = evaluated
182 |
183 | # Deregister a timeline trigger once it has fired because we can't go back in time
184 | @deregisterTrigger trigger if trigger.type == N3Trigger.TYPES.TIMELINE && evaluated != false
185 | true
186 |
187 | @parseTransSyntax: (transQ) ->
188 | return transQ if transQ instanceof Array
189 |
190 | scenes = []
191 |
192 | if transQ == '*'
193 | for sceneId of N3Scene.scenes
194 | scenes.push sceneId
195 |
196 | scene = N3Scene.scenes[sceneId]
197 | for subSceneId of scene.subScenes
198 | scenes.push subSceneId
199 | else if transQ.indexOf('>') != -1 # Subscening
200 | scenes.push (id.trim() for id in transQ.split('>')).join('>')
201 | else # To allow individual sceneIds just to be passed without being arrays
202 | scenes.push transQ
203 |
204 | return scenes
205 |
206 | @transition: (fromScenes, toScenes, func) ->
207 | fromScenes = @parseTransSyntax fromScenes
208 | toScenes = @parseTransSyntax toScenes
209 |
210 | for fromScene in fromScenes
211 | # Allow people to pass in scene objs too
212 | fromSceneId = if typeof fromScene == 'object' then fromScene.sceneId else fromScene
213 |
214 | @transitions[fromSceneId] or= {}
215 |
216 | for toScene in toScenes
217 | # Allow people to pass in scene objs too
218 | toSceneId = if typeof toScene == 'object' then toScene.sceneId else toScene
219 |
220 | @transitions[fromSceneId][toSceneId] or= []
221 | @transitions[fromSceneId][toSceneId].push func
222 |
223 | return this
224 |
225 |
226 | @start: (reset) ->
227 | if reset
228 | @startTime = Date.now()
229 | @elapsedTime = 0
230 |
231 | @paused = false
232 | d3.timer(=> @incrementTime())
233 |
234 | @incrementTime: ->
235 | @elapsedTime = Date.now() - @startTime
236 | N3Trigger.notify(N3Trigger.TYPES.TIMELINE, N3Trigger.WHERE.ELAPSED, @elapsedTime)
237 |
238 | return @paused
239 |
240 | @pause: ->
241 | @paused = true
242 |
243 | n3.timeline or= {}
244 | n3.timeline.switchScene = (sceneId) ->
245 | N3Timeline.switchScene(sceneId)
246 |
247 | n3.timeline.pause = ->
248 | N3Timeline.pause()
249 |
250 | n3.timeline.resume = ->
251 | N3Timeline.start(false)
252 |
253 | n3.timeline.elapsedTime = ->
254 | N3Timeline.elapsedTime
255 |
256 | n3.timeline.transition = (fromScenes, toScenes, func) ->
257 | N3Timeline.transition(fromScenes, toScenes, func)
--------------------------------------------------------------------------------
/src/trigger.coffee:
--------------------------------------------------------------------------------
1 | class N3Trigger
2 | @TYPES =
3 | VIS: 'vis'
4 | TIMELINE: 'timeline'
5 | DELAY: 'delay'
6 | DOM: 'dom'
7 | OR: 'or'
8 | AND: 'and'
9 |
10 | @CONDITIONS =
11 | IS: 'is'
12 | NOT: 'not'
13 | GT: 'gt'
14 | LT: 'lt'
15 | GTE: 'gte'
16 | LTE: 'lte'
17 |
18 | @WHERE =
19 | ELAPSED: 'elapsed'
20 | DELAY: 'delay_'
21 |
22 | @registered = {}
23 |
24 | @register = (trigger) ->
25 | success = true
26 |
27 | @registered[trigger.type] or= {}
28 | @registered[trigger.type][trigger.test] or= {}
29 | @registered[trigger.type][trigger.test][trigger.triggerId] = trigger
30 |
31 | # If we're a OR or AND trigger, register the individual sub-triggers
32 | # for fast look up, but have them point to the parent OR/AND trigger
33 | if trigger.type == @TYPES.OR or trigger.type == @TYPES.AND
34 | if trigger.triggers?
35 | for t in trigger.triggers
36 | @registered[t.type] or= {}
37 | @registered[t.type][t.test] or= {}
38 | @registered[t.type][t.test][t.triggerId] = trigger
39 |
40 | if t.type == @TYPES.DOM
41 | success = @bindDomTrigger(t)
42 |
43 | # If we're listening for a DOM event, use d3 to add an event listener
44 | # to the DOM node
45 | if trigger.type == @TYPES.DOM
46 | success = @bindDomTrigger(trigger)
47 |
48 | return success
49 |
50 | @deregister = (trigger) ->
51 | [type, test, triggerId] = [trigger.type, trigger.test, trigger.triggerId]
52 |
53 | trigger = @registered[type][test]?[triggerId]
54 |
55 | # If the trigger was a DOM event, use d3 to remove the event listener
56 | if type == @TYPES.DOM
57 | d3.select(trigger.test)
58 | .on(trigger.value, null)
59 |
60 | delete @registered[type][test]?[triggerId]
61 |
62 | true
63 |
64 | @bindDomTrigger = (trigger) ->
65 | elems = d3.select(trigger.test)
66 | return false unless elems[0][0]? # If elem doesn't exist, defer registration
67 |
68 | d3.select(trigger.test)
69 | .on(trigger.value, =>
70 | return n3.trigger.notify(@TYPES.DOM, trigger.test, trigger.value)
71 | )
72 |
73 | true
74 |
75 | @notify = (type, test, value) ->
76 | if @registered[type]?[test]?
77 | for triggerId, trigger of @registered[type][test]
78 | eval = trigger.evaluate(test, value);
79 | N3Timeline.notifyTrigger(trigger, eval)
80 |
81 | true;
82 |
83 |
84 | constructor: (binding, triggers...) ->
85 | if arguments.length == 1 # Only a single trigger
86 | if typeof binding == 'object' # could be an n3.vis or n3.timeline
87 | if binding.visId?
88 | @type = N3Trigger.TYPES.VIS
89 | @test or= [binding.visId, undefined]
90 | else
91 | @type = N3Trigger.TYPES.TIMELINE
92 | else if typeof binding == 'string' # could be a visID or a dom selector
93 | if N3Vis.lookup[binding]?
94 | @type = N3Trigger.TYPES.VIS
95 | @test or= [binding, undefined]
96 | else
97 | @type = N3Trigger.TYPES.DOM
98 | @test = binding
99 | else # n3.trigger.or / n3.trigger.and
100 | @type = binding
101 | @triggers = triggers
102 |
103 | @triggerId = @type + @test + '' + Date.now() + (Math.random() * 11)
104 |
105 | return this
106 |
107 | where: (test) ->
108 | if @type == N3Trigger.TYPES.VIS
109 | @test[1] = test
110 | else
111 | @test = test
112 |
113 | return this
114 |
115 | is: (@value) ->
116 | @condition = N3Trigger.CONDITIONS.IS
117 |
118 | return this
119 |
120 | not: (@value) ->
121 | @condition = N3Trigger.CONDITIONS.NOT
122 |
123 | return this
124 |
125 | gt: (@value) ->
126 | @condition = N3Trigger.CONDITIONS.GT
127 |
128 | return this
129 |
130 | greaterThan: (@value) ->
131 | @gt @value
132 |
133 | lt: (@value) ->
134 | @condition = N3Trigger.CONDITIONS.LT
135 |
136 | return this
137 |
138 | lessThan: (@value) ->
139 | @lt @value
140 |
141 | gte: (@value) ->
142 | @condition = N3Trigger.CONDITIONS.GTE
143 |
144 | return this
145 |
146 | greaterThanOrEqual: (@value) ->
147 | @gte @value
148 |
149 | lte: (@value) ->
150 | @condition = N3Trigger.CONDITIONS.LTE
151 |
152 | return this
153 |
154 | lessThanOrEqual: (@value) ->
155 | @lte @value
156 |
157 | on: (@value) ->
158 | return this
159 |
160 | # Delay triggers always evaluate as false but a d3.timer registers that calls
161 | # this function to manually notify the timeline.
162 | fireDelay: () ->
163 | N3Timeline.notifyTrigger(this, true)
164 | return true
165 |
166 | evaluate: (notifiedTest, notifiedVal, parent) ->
167 | if @type == N3Trigger.TYPES.DOM
168 | return true
169 | else if @type == N3Trigger.TYPES.OR
170 | for trigger in @triggers
171 | result = if (trigger.test + "") == (notifiedTest + "") then trigger.evaluate(notifiedTest, notifiedVal, this) else false
172 | return true if result == true # If at least one is true, then return
173 | # If we've made it through all triggers without
174 | return false # returning, then none of them were true
175 | else if @type == N3Trigger.TYPES.AND
176 | for trigger in @triggers
177 | result = if (trigger.test + "") == (notifiedTest + "") then trigger.evaluate(notifiedTest, notifiedVal, this) else false
178 |
179 | # In AND triggers, we want to check the ambient value of states
180 | # because they may have been triggered previously
181 | if result == false and trigger.type == N3Trigger.TYPES.VIS
182 | result = trigger.evaluate(trigger.test, N3Vis.lookup[trigger.test[0]]?.state(trigger.test[1]))
183 |
184 | return false if result == false # If at least one is false, then return
185 | # If we've made it through all triggers without
186 | return true # returning, then none of them were false
187 | else if @type == N3Trigger.TYPES.DELAY # If it's a delay, register a timer
188 | c = => return if parent? then parent.fireDelay() else @fireDelay()
189 | d3.timer(c, @value) # and evaluate this trigger as false
190 | return false
191 | else
192 | return true if (@type == N3Trigger.TYPES.DOM) or
193 | (@condition == N3Trigger.CONDITIONS.IS and notifiedVal == @value) or \
194 | (@condition == N3Trigger.CONDITIONS.NOT and notifiedVal != @value) or \
195 | (@condition == N3Trigger.CONDITIONS.GT and notifiedVal > @value) or \
196 | (@condition == N3Trigger.CONDITIONS.LT and notifiedVal < @value) or \
197 | (@condition == N3Trigger.CONDITIONS.GTE and notifiedVal >= @value) or \
198 | (@condition == N3Trigger.CONDITIONS.LTE and notifiedVal <= @value)
199 |
200 | return false
201 |
202 | n3.trigger = (binding) ->
203 | new N3Trigger(binding)
204 |
205 | n3.trigger.or = (triggers...) ->
206 | new N3Trigger(N3Trigger.TYPES.OR, triggers...)
207 |
208 | n3.trigger.and = (triggers...) ->
209 | new N3Trigger(N3Trigger.TYPES.AND, triggers...)
210 |
211 | n3.trigger.notify = (type, test, value) ->
212 | N3Trigger.notify(type, test, value)
213 |
214 | n3.trigger.afterPrev = (delay) ->
215 | t = new N3Trigger(N3Trigger.TYPES.DELAY, N3Trigger.WHERE.DELAY)
216 | t.gte(delay)
--------------------------------------------------------------------------------
/src/util.coffee:
--------------------------------------------------------------------------------
1 | n3.util = {}
2 |
3 | n3.util.getSelector = (selector, attrs) ->
4 | if attrs?.id?
5 | selector + '#' + attrs['id']
6 | else if attrs?.class?
7 | selector + '.' + attrs['class'].split(' ').join('.')
8 | else
9 | selector
10 |
11 | n3.util.clone = (obj) ->
12 | return obj unless obj? and typeof obj == 'object'
13 |
14 | if obj instanceof Array
15 | copy = (n3.util.clone elem for elem in obj)
16 |
17 | else if obj instanceof Object
18 | copy = {}
19 | copy[key] = n3.util.clone val for key, val of obj
20 |
21 | return copy
22 |
23 | n3.util.iterate = (args...) ->
24 | arr = []
25 | step = args[args.length - 2]
26 | delay = args[args.length - 1]
27 |
28 | if arguments.length == 3
29 | arr = args[0]
30 | else if arguments.length == 4
31 | arr = d3.range(args[0], args[1], step)
32 |
33 | return (vis, stateId) ->
34 | currIndex = 0
35 |
36 | callback = ->
37 | vis.state(stateId, arr[currIndex++])
38 | window.clearInterval(interval) if currIndex >= arr.length
39 |
40 | interval = window.setInterval(callback, delay)
41 | false
--------------------------------------------------------------------------------
/src/version.coffee:
--------------------------------------------------------------------------------
1 | window.n3 =
2 | version: '0.9.0'
--------------------------------------------------------------------------------
/src/vis.coffee:
--------------------------------------------------------------------------------
1 | class N3Vis
2 | @lookup = {} # static lookup table visId -> N3Vis
3 |
4 | constructor: (@visId) ->
5 | @states = {} # lookup table stateId -> N3State
6 | @consts = {} # lookup table constId -> constVal
7 |
8 | return this
9 |
10 | id: ->
11 | @visId
12 |
13 | stage: (sel, w, h) ->
14 | if arguments.length == 3
15 | @stageSelector = sel
16 | @stageWidth = w
17 | @stageHeight = h
18 |
19 | return this
20 | else
21 | d3.select(@stageSelector)
22 |
23 | width: (width) ->
24 | if arguments.length == 1
25 | @stageWidth = width
26 |
27 | return this
28 | else
29 | @stageWidth
30 |
31 | height: (height) ->
32 | if arguments.length == 1
33 | @stageHeight = height
34 |
35 | return this
36 | else
37 | @stageHeight
38 |
39 | data: (data) ->
40 | if arguments.length == 1
41 | @dataObj = data
42 |
43 | return this
44 | else
45 | return if typeof @dataObj == 'function' then @dataObj() else @dataObj
46 |
47 | state: (stateId, arg2) ->
48 | if arguments.length >= 2 # state can be a setter
49 | if arg2 instanceof Array # or a definition of a new state
50 | @states[stateId] = new N3State(@visId, stateId, arg2, arguments[2])
51 | else
52 | throw "no such state '#{stateId}'" unless @states[stateId]?
53 | @states[stateId]?.set(arg2)
54 |
55 | return this
56 | else
57 | throw "no such state '#{stateId}'" unless @states[stateId]?
58 | @states[stateId]?.get()
59 |
60 | const: (constId, value) ->
61 | if arguments.length == 2
62 | # consts are read only, so only add them if they haven't already
63 | # been defined
64 | @consts[constId] = value unless constId of @consts
65 |
66 | return this
67 | else
68 | @consts[constId]
69 | # We don't actually want to call the function because people are probably
70 | # expecting a fn ptr returned.
71 | # if typeof constVal == 'function' then constVal.apply(this) else constVal
72 |
73 | bind: (stateId, funcPtr) ->
74 | throw "no such state '#{stateId}'" unless @states[stateId]?
75 |
76 | @states[stateId]?.bind(funcPtr)
77 |
78 | return this
79 |
80 | render: (@renderFn) ->
81 | return this
82 |
83 | n3.vis = (visId) ->
84 | N3Vis.lookup[visId] or= new N3Vis(visId)
--------------------------------------------------------------------------------
/test/annotation.test.coffee:
--------------------------------------------------------------------------------
1 | describe 'annotation', ->
2 | vis = null
3 |
4 | beforeEach ->
5 | d3.select('body')
6 | .append('svg:svg')
7 | .attr('id', 'stage')
8 | .attr('width', 500)
9 | .attr('height', 600)
10 |
11 | vis = n3.vis('annotation_test')
12 | .stage('#stage', 500, 600)
13 |
14 | afterEach ->
15 | vis = null
16 | d3.selectAll('#stage').remove()
17 |
18 | it 'sets/gets the vis', ->
19 | a = n3.annotation('custom').vis(vis)
20 |
21 | expect(a.vis().stage()).toEqual d3.select('#stage')
22 | expect(a.vis().width()).toBe 500
23 | expect(a.vis().height()).toBe 600
24 |
25 | it 'sets/gets data', ->
26 | d = ['do', 're', 'mi', 'fa', 'so']
27 |
28 | # Testing if .data() sets and is chainable
29 | expect(n3.annotation('custom').data(d).data()).toBe d
30 |
31 | # Testing if .data() supports different data types
32 | d1 = {Jagger: 'Rock', Elvis: 'Roll'}
33 | expect(n3.annotation('custom').data(d1).data()).toBe d1
34 |
35 | d2 =
36 | brother:
37 | name: 'Max'
38 | age: 11
39 | sister:
40 | name: 'Ida'
41 | age: 9
42 |
43 | expect(n3.annotation('custom').data(d2).data()).toBe d2
44 |
45 | # Tests that .data is not set for another vis
46 | expect(n3.annotation('custom2').data()).toBeUndefined
47 |
48 | it 'is a custom annotation', ->
49 | f = (arg1, arg2) ->
50 | console.log('Arg1: ' + arg1 + ' Arg2: ' + arg2)
51 |
52 | f1 = (arg1, arg2) ->
53 | console.log('F1Arg1: ' + arg1 + ' F1Arg2: ' + arg2)
54 |
55 | a = n3.annotation('custom')
56 | expect(a.enterFn).toBeUndefined
57 |
58 | a.enter(f)
59 | .exit(f1)
60 | .args('hello', [1, 2, 3], { 'foo': 'bar' }, 'world')
61 |
62 | expect(a.enterFn).toBe f
63 | expect(a.exitFn).toBe f1
64 |
65 | spyOn(a, 'enterFn')
66 | a.add()
67 | expect(a.enterFn).toHaveBeenCalledWith('hello', [1, 2, 3], { 'foo': 'bar' }, 'world')
68 |
69 | spyOn(a, 'exitFn')
70 | a.remove()
71 | expect(a.exitFn).toHaveBeenCalledWith('hello', [1, 2, 3], { 'foo': 'bar' }, 'world')
72 |
73 | it 'is a circle', ->
74 | a = n3.annotation('circle')
75 | .center([15, 45])
76 | .radius(5)
77 | .data([1]) # to test chaining
78 |
79 | spyOn(a, 'enterFn')
80 | a.add()
81 | expect(a.enterFn).toHaveBeenCalledWith(5, [15, 45])
82 |
83 | spyOn(a, 'exitFn')
84 | a.remove()
85 | expect(a.exitFn).toHaveBeenCalledWith(5, [15, 45])
86 |
87 | it 'draws a circle', ->
88 | a = n3.annotation('circle')
89 | .center([15, 45])
90 | .radius(5)
91 | .vis(vis)
92 |
93 | a.add()
94 |
95 | c = vis.stage().selectAll('circle')
96 | expect(c.attr('r')).toBe '5'
97 | expect(c.attr('cx')).toBe '15'
98 | expect(c.attr('cy')).toBe '45'
99 |
100 | it 'is an ellipse', ->
101 | a = n3.annotation('ellipse')
102 | .radius([3, 7])
103 | .center([11, 21])
104 | .data([2]) # to test chaining
105 |
106 | spyOn(a, 'enterFn')
107 | a.add()
108 | expect(a.enterFn).toHaveBeenCalledWith([3, 7], [11, 21])
109 |
110 | spyOn(a, 'exitFn')
111 | a.remove()
112 | expect(a.exitFn).toHaveBeenCalledWith([3, 7], [11, 21])
113 |
114 | it 'draws an ellipse', ->
115 | a = n3.annotation('ellipse')
116 | .radius([3, 7])
117 | .center([11, 21])
118 | .vis(vis)
119 |
120 | a.add()
121 |
122 | e = vis.stage().selectAll('ellipse')
123 | expect(e.attr('rx')).toBe '3'
124 | expect(e.attr('ry')).toBe '7'
125 | expect(e.attr('cx')).toBe '11'
126 | expect(e.attr('cy')).toBe '21'
127 |
128 | it 'is a line', ->
129 | a = n3.annotation('line')
130 | .start([6, 8], true)
131 | .end([32, 12], false)
132 | .data([3]) # to test chaining
133 |
134 | spyOn(a, 'enterFn')
135 | a.add()
136 | expect(a.enterFn).toHaveBeenCalledWith([6, 8], true, [32, 12], false)
137 |
138 | spyOn(a, 'exitFn')
139 | a.remove()
140 | expect(a.exitFn).toHaveBeenCalledWith([6, 8], true, [32, 12], false)
141 |
142 | it 'draws a line', ->
143 | a = n3.annotation('line')
144 | .start([6, 8], true)
145 | .end([32, 12], false)
146 | .vis(vis)
147 |
148 | a.add()
149 |
150 | l = vis.stage().selectAll('line')
151 | expect(l.attr('x1')).toBe '6'
152 | expect(l.attr('y1')).toBe '8'
153 | expect(l.attr('x2')).toBe '32'
154 | expect(l.attr('y2')).toBe '12'
155 |
156 | it 'is a rectangle', ->
157 | a = n3.annotation('rectangle')
158 | .pos([17, 14])
159 | .size([42, 91])
160 | .data([4]) # to test chaining
161 |
162 | spyOn(a, 'enterFn')
163 | a.add()
164 | expect(a.enterFn).toHaveBeenCalledWith([42, 91], [17, 14])
165 |
166 | spyOn(a, 'exitFn')
167 | a.remove()
168 | expect(a.exitFn).toHaveBeenCalledWith([42, 91], [17, 14])
169 |
170 | it 'draws a rectangle', ->
171 | a = n3.annotation('rectangle')
172 | .pos([17, 14])
173 | .size([42, 91])
174 | .vis(vis)
175 |
176 | a.add()
177 |
178 | r = vis.stage().selectAll('rect')
179 | expect(r.attr('width')).toBe '42'
180 | expect(r.attr('height')).toBe '91'
181 | expect(r.attr('x')).toBe '17'
182 | expect(r.attr('y')).toBe '14'
183 |
184 | it 'is a label', ->
185 | a = n3.annotation('label')
186 | .html('Hello
')
187 | .text('world')
188 | .pos([3, 7])
189 | .data([4]) # to test chaining
190 |
191 | spyOn(a, 'enterFn')
192 | a.add()
193 | expect(a.enterFn).toHaveBeenCalledWith('world', 'Hello
', [3, 7])
194 |
195 | spyOn(a, 'exitFn')
196 | a.remove()
197 | expect(a.exitFn).toHaveBeenCalledWith('world', 'Hello
', [3, 7])
198 |
199 | it 'draws a label', ->
200 | a = n3.annotation('label')
201 | .html('Hello
')
202 | .text('world')
203 | .pos([3, 7])
204 | .attr('id', 'label')
205 | .vis(vis)
206 |
207 | a.add()
208 |
209 | d = d3.selectAll('div#label')
210 |
211 | expect(d.style('position')).toBe 'absolute'
212 | expect(d.style('left')).toBe '11px'
213 | expect(d.style('top')).toBe '15px'
214 | expect(d.html()).toBe 'Hello
'
215 |
216 | it 'sets/gets attrs', ->
217 | a = n3.annotation('circle')
218 | .center([15, 45])
219 | .radius(5)
220 | .attr('foo', 'baz')
221 | .attr('r', '15')
222 | .style('position', 'absolute')
223 | .vis(vis)
224 |
225 | a.add()
226 |
227 | c = vis.stage().selectAll('circle')
228 | expect(c.attr('foo')).toBe 'baz'
229 | expect(c.attr('r')).toBe '15'
230 |
231 | it 'sets/gets styles', ->
232 | a = n3.annotation('circle')
233 | .center([15, 45])
234 | .radius(5)
235 | .style('display', 'none')
236 | .style('fill', '#ffffff')
237 | .vis(vis)
238 |
239 | a.add()
240 |
241 | c = vis.stage().selectAll('circle')
242 | expect(c.style('display')).toBe 'none'
243 | expect(c.style('fill')).toBe '#FFFFFF'
244 |
--------------------------------------------------------------------------------
/test/domTimingTest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | N3 System Test
5 |
6 |
7 |
35 |
36 |
37 |
38 | 1
39 | 2
40 | 3
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
Scene One
49 |
50 |
Hong Kong Phooey, number one super guy. Hong Kong Phooey, quicker than the human eye. He's got style, a groovy style, and a car that just won't stop. When the going gets tough, he's really rough, with a Hong Kong Phooey chop (Hi-Ya!). Hong Kong Phooey, number one super guy. Hong Kong Phooey, quicker than the human eye. Hong Kong Phooey, he's fan-riffic!
51 |
52 |
53 |
54 |
Scene Two
55 |
56 |
Knight Rider , a shadowy flight into the dangerous world of a man who does not exist. Michael Knight, a young loner on a crusade to champion the cause of the innocent, the helpless in a world of criminals who operate above the law.
57 |
58 |
59 |
60 |
Scene Three
61 |
62 |
Thunder, thunder, thundercats, Ho! Thundercats are on the move, Thundercats are loose. Feel the magic, hear the roar, Thundercats are loose. Thunder, thunder, thunder, Thundercats! Thunder, thunder, thunder, Thundercats! Thunder, thunder, thunder, Thundercats! Thunder, thunder, thunder, Thundercats! Thundercats!
63 |
64 |
65 |
66 |
156 |
--------------------------------------------------------------------------------
/test/scene.test.coffee:
--------------------------------------------------------------------------------
1 | describe "scene", ->
2 | vis = null
3 | scene = null
4 | f = null
5 | a = null
6 |
7 | beforeEach ->
8 | vis = n3.vis('sceneTest')
9 | .state('state_1', ['valid', 'values'])
10 | .state('state_2', [true, false])
11 | .render(->
12 | console.log('render!');
13 | )
14 |
15 | f = ->
16 | console.log('hello')
17 |
18 | a = n3.annotation('f')
19 | .enter(f)
20 |
21 | it "sets the state", ->
22 | scene = n3.scene('scene_1')
23 | .set(vis, 'state_1', 'valid')
24 | .set('sceneTest', 'state_2', false)
25 |
26 | expect(scene.members[0].visId).toBe vis.visId
27 | expect(scene.members[0].state.id).toBe 'state_1'
28 | expect(scene.members[0].state.value).toBe 'valid'
29 |
30 | expect(scene.members[1].visId).toBe vis.visId
31 | expect(scene.members[1].state.id).toBe 'state_2'
32 | expect(scene.members[1].state.value).toBe false
33 |
34 | it "adds members", ->
35 | scene = n3.scene('scene_2')
36 | .add(vis, f)
37 | .add(vis, a)
38 |
39 | expect(scene.members[0].visId).toBe vis.visId
40 | expect(scene.members[0].member).toBe f
41 |
42 | expect(scene.members[1].visId).toBe vis.visId
43 | expect(scene.members[1].member).toBe a
44 |
45 | it "evaluates members", ->
46 | scene = n3.scene('scene_3')
47 | .set(vis, 'state_1', 'values')
48 | .add(vis, f)
49 | .set(vis, 'state_2', true)
50 | .add(vis, a)
51 |
52 | spyOn(vis, 'renderFn')
53 | scene.evalMember(0)
54 | expect(vis.state('state_1')).toBe 'values'
55 | expect(vis.renderFn).toHaveBeenCalledWith()
56 |
57 | spyOn(scene.members[1], 'member')
58 | scene.evalMember(1)
59 | expect(vis.renderFn.callCount).toBe 1 # adding an annotation shouldn't re-render
60 | expect(scene.members[1].member).toHaveBeenCalledWith(vis)
61 |
62 | scene.evalMember(2)
63 | expect(vis.state('state_2')).toBe true
64 | expect(vis.renderFn).toHaveBeenCalledWith()
65 | expect(vis.renderFn.callCount).toBe 2
66 |
67 | spyOn(a, 'enterFn')
68 | scene.evalMember(3)
69 | expect(a.enterFn).toHaveBeenCalledWith()
70 |
71 |
72 | it "clones a scene", ->
73 | scene = n3.scene('scene_4')
74 | .set(vis, 'state_1', 'values')
75 | .add(vis, f)
76 | .set(vis, 'state_2', true)
77 |
78 | scene2 = scene.clone('scene_5')
79 | .add('sceneTest', a)
80 |
81 | expect(scene2.members[0].visId).toBe vis.visId
82 | expect(scene2.members[0].state.id).toBe 'state_1'
83 | expect(scene2.members[0].state.value).toBe 'values'
84 |
85 | spyOn(vis, 'renderFn')
86 | scene2.evalMember(0)
87 | expect(vis.state('state_1')).toBe 'values'
88 | expect(vis.renderFn).toHaveBeenCalledWith()
89 |
90 | expect(scene2.members[1].visId).toBe vis.visId
91 | expect(scene2.members[1].member).toBe f
92 |
93 | spyOn(scene2.members[1], 'member')
94 | scene2.evalMember(1)
95 | expect(vis.renderFn.callCount).toBe 1 # adding an annotation shouldn't re-render
96 | expect(scene2.members[1].member).toHaveBeenCalledWith(vis)
97 |
98 | expect(scene2.members[2].visId).toBe vis.visId
99 | expect(scene2.members[2].state.id).toBe 'state_2'
100 | expect(scene2.members[2].state.value).toBe true
101 |
102 | scene2.evalMember(2)
103 | expect(vis.state('state_2')).toBe true
104 | expect(vis.renderFn).toHaveBeenCalledWith()
105 | expect(vis.renderFn.callCount).toBe 2
106 |
107 | expect(scene2.members[3].visId).toBe vis.visId
108 | expect(scene2.members[3].member).toBe a
109 |
110 | spyOn(a, 'enterFn')
111 | scene2.evalMember(3)
112 | expect(a.enterFn).toHaveBeenCalledWith()
113 |
114 | it "is a subscene", ->
115 | scene = n3.scene('scene_6')
116 | .set(vis, 'state_1', 'value')
117 | .add(vis, f)
118 |
119 | subScene = scene.subScene('scene_6a')
120 | .set(vis, 'state_2', true)
121 | .add(vis, a)
122 |
123 | expect(subScene.parent).toBe scene
124 |
125 | expect(subScene.members[0].visId).toBe vis.visId
126 | expect(subScene.members[0].state.id).toBe 'state_2'
127 | expect(subScene.members[0].state.value).toBe true
128 |
129 | spyOn(vis, 'renderFn')
130 | subScene.evalMember(0)
131 | expect(vis.state('state_2')).toBe true
132 | expect(vis.renderFn).toHaveBeenCalledWith()
133 | expect(vis.renderFn.callCount).toBe 1
134 |
135 | expect(subScene.members[1].visId).toBe vis.visId
136 | expect(subScene.members[1].member).toBe a
137 |
138 | spyOn(a, 'enterFn')
139 | subScene.evalMember(1)
140 | expect(a.enterFn).toHaveBeenCalledWith()
--------------------------------------------------------------------------------
/test/support/jasmine.yml:
--------------------------------------------------------------------------------
1 | # src_files
2 | #
3 | # Return an array of filepaths relative to src_dir to include before jasmine specs.
4 | # Default: []
5 | #
6 | # EXAMPLE:
7 | #
8 | # src_files:
9 | # - lib/source1.js
10 | # - lib/source2.js
11 | # - dist/**/*.js
12 | #
13 | src_files:
14 | - n3.js
15 |
16 | # stylesheets
17 | #
18 | # Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
19 | # Default: []
20 | #
21 | # EXAMPLE:
22 | #
23 | # stylesheets:
24 | # - css/style.css
25 | # - stylesheets/*.css
26 | #
27 | stylesheets:
28 |
29 | # helpers
30 | #
31 | # Return an array of filepaths relative to spec_dir to include before jasmine specs.
32 | # Default: ["helpers/**/*.js"]
33 | #
34 | # EXAMPLE:
35 | #
36 | # helpers:
37 | # - helpers/**/*.js
38 | #
39 | helpers:
40 | - ../node_modules/d3/d3.v2.js
41 |
42 | # spec_files
43 | #
44 | # Return an array of filepaths relative to spec_dir to include.
45 | # Default: ["**/*[sS]pec.js"]
46 | #
47 | # EXAMPLE:
48 | #
49 | # spec_files:
50 | # - **/*[sS]pec.js
51 | #
52 | spec_files:
53 | - *.test.coffee
54 |
55 | # src_dir
56 | #
57 | # Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
58 | # Default: project root
59 | #
60 | # EXAMPLE:
61 | #
62 | # src_dir: public
63 | #
64 | src_dir:
65 |
66 | # spec_dir
67 | #
68 | # Spec directory path. Your spec_files must be returned relative to this path.
69 | # Default: spec/javascripts
70 | #
71 | # EXAMPLE:
72 | #
73 | # spec_dir: spec/javascripts
74 | #
75 | spec_dir: test
76 |
--------------------------------------------------------------------------------
/test/support/jasmine_config.rb:
--------------------------------------------------------------------------------
1 | module Jasmine
2 | class Config
3 |
4 | # Add your overrides or custom config code here
5 |
6 | end
7 | end
8 |
9 |
10 | # Note - this is necessary for rspec2, which has removed the backtrace
11 | module Jasmine
12 | class SpecBuilder
13 | def declare_spec(parent, spec)
14 | me = self
15 | example_name = spec["name"]
16 | @spec_ids << spec["id"]
17 | backtrace = @example_locations[parent.description + " " + example_name]
18 | parent.it example_name, {} do
19 | me.report_spec(spec["id"])
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/support/jasmine_runner.rb:
--------------------------------------------------------------------------------
1 | $:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
2 |
3 | require 'rubygems'
4 | require 'jasmine'
5 | jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
6 | require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
7 | if Jasmine::Dependencies.rspec2?
8 | require 'rspec'
9 | else
10 | require 'spec'
11 | end
12 |
13 | jasmine_config = Jasmine::Config.new
14 | spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
15 |
16 | should_stop = false
17 |
18 | if Jasmine::Dependencies.rspec2?
19 | RSpec.configuration.after(:suite) do
20 | spec_builder.stop if should_stop
21 | end
22 | else
23 | Spec::Runner.configure do |config|
24 | config.after(:suite) do
25 | spec_builder.stop if should_stop
26 | end
27 | end
28 | end
29 |
30 | spec_builder.start
31 | should_stop = true
32 | spec_builder.declare_suites
33 |
--------------------------------------------------------------------------------
/test/timeline.test.coffee:
--------------------------------------------------------------------------------
1 | describe "timeline", ->
2 | scene1 = null
3 | scene2 = null
4 | vis = null
5 |
6 | beforeEach ->
7 | d3.select('body')
8 | .append('svg:svg')
9 | .attr('id', 'stage')
10 | .attr('width', 500)
11 | .attr('height', 600)
12 |
13 | vis = n3.vis('visTimelineTest')
14 | .stage('#stage', 500, 600)
15 | .state('state_1', ['valid', 'values'])
16 | .state('state_2', [true, false])
17 | .render(->
18 | console.log('timelineTest render');
19 | )
20 |
21 | afterEach ->
22 | vis = null
23 | d3.selectAll('#stage').remove()
24 |
25 | # Simple scene switching, tests that members are added/removed
26 | it "switches simple scenes", ->
27 | scene1 = n3.scene('timelineScene_1')
28 | .set('visTimelineTest', 'state_1', 'valid')
29 | .add('visTimelineTest', n3.annotation('circle')
30 | .radius(5)
31 | .center([1, 2])
32 | .attr('id', 'hello'))
33 | .set('visTimelineTest', 'state_2', true)
34 | .add('visTimelineTest', n3.annotation('circle')
35 | .radius(7)
36 | .center([8, 4])
37 | .attr('id', 'goodbye')
38 | .autoExit(false))
39 |
40 | scene2 = n3.scene('timelineScene_2')
41 | .add('visTimelineTest', n3.annotation('rectangle')
42 | .size([5, 15])
43 | .pos([1, 11]))
44 | .set('visTimelineTest', 'state_1', 'values')
45 | .set('visTimelineTest', 'state_2', false)
46 |
47 | n3.timeline.switchScene('timelineScene_1')
48 | expect(vis.state('state_1')).toBe 'valid'
49 | expect(vis.state('state_2')).toBe true
50 | expect(d3.selectAll('circle')[0].length).toBe 2
51 |
52 | n3.timeline.switchScene('timelineScene_2')
53 | expect(vis.state('state_1')).toBe 'values'
54 | expect(vis.state('state_2')).toBe false
55 | expect(d3.selectAll('circle')[0].length).toBe 1
56 | expect(d3.selectAll('rect')[0].length).toBe 1
57 |
58 | it "registers and fires triggers", ->
59 | n3.timeline.switchScene('timelineScene_1')
60 | n3.timeline.switchScene('timelineScene_2')
61 |
62 | scene3 = n3.scene('timelineScene_3')
63 | .add(vis,
64 | n3.annotation('ellipse')
65 | .attr('id', 'foo')
66 | .radius([1, 2])
67 | .center([3, 4]),
68 | n3.trigger(vis)
69 | .where('state_1')
70 | .is('valid'))
71 | .add(vis,
72 | n3.annotation('line')
73 | .attr('id', 'bar')
74 | .start([1, 2])
75 | .end([3, 4]),
76 | n3.trigger(vis)
77 | .where('state_2')
78 | .is(true))
79 |
80 | n3.timeline.switchScene('timelineScene_3')
81 | expect(vis.state('state_1')).toBe 'values'
82 | expect(vis.state('state_2')).toBe false
83 | vis.state('state_2', true)
84 | expect(d3.selectAll('circle')[0].length).toBe 1
85 | expect(d3.selectAll('rect')[0].length).toBe 0
86 | expect(d3.selectAll('ellipse')[0].length).toBe 0
87 | expect(d3.selectAll('line')[0].length).toBe 1
88 |
89 | vis.state('state_1', 'valid')
90 | expect(d3.selectAll('ellipse')[0].length).toBe 1
91 |
92 | it "delay triggers", ->
93 | vis.state('state_1', 'valid')
94 | vis.state('state_2', true)
95 |
96 | n3.timeline.switchScene('timelineScene_1')
97 |
98 | expect(d3.selectAll('circle')[0].length).toBe 2
99 | expect(d3.selectAll('rect')[0].length).toBe 0
100 | expect(d3.selectAll('ellipse')[0].length).toBe 0
101 | expect(d3.selectAll('line')[0].length).toBe 0
102 |
103 | expect(vis.state('state_1')).toBe 'valid'
104 | expect(vis.state('state_2')).toBe true
105 |
106 | scene4 = n3.scene('timelineScene_4')
107 | .add(vis,
108 | n3.annotation('ellipse')
109 | .attr('id', 'foo')
110 | .radius([1, 2])
111 | .center([3, 4]),
112 | n3.trigger(vis)
113 | .where('state_1')
114 | .is('values'))
115 | .add(vis,
116 | n3.annotation('line')
117 | .attr('id', 'bar')
118 | .start([1, 2])
119 | .end([3, 4]),
120 | n3.trigger.afterPrev(1))
121 |
122 | n3.timeline.switchScene('timelineScene_4')
123 | expect(d3.selectAll('ellipse')[0].length).toBe 0
124 | expect(d3.selectAll('line')[0].length).toBe 0
125 |
126 | vis.state('state_2', false)
127 | expect(vis.state('state_2')).toBe false
128 | expect(d3.selectAll('circle')[0].length).toBe 1
129 | expect(d3.selectAll('rect')[0].length).toBe 0
130 | expect(d3.selectAll('ellipse')[0].length).toBe 0
131 | expect(d3.selectAll('line')[0].length).toBe 0
132 |
133 | vis.state('state_1', 'values')
134 | expect(d3.selectAll('ellipse')[0].length).toBe 1
135 | # expect(d3.selectAll('line')[0].length).toBe 1
136 |
137 | it "transitions scenes", ->
138 | n3.timeline.switchScene('timelineScene_1')
139 |
140 | t1 = (fromScene, toScene) ->
141 | console.log('t1: ' + fromScene.sceneId + ' -> ' + toScene.sceneId)
142 |
143 | t2 = (fromScene, toScene) ->
144 | console.log('t2: ' + fromScene.sceneId + ' -> ' + toScene.sceneId)
145 |
146 | t3 = (fromScene, toScene) ->
147 | console.log('t3: ' + fromScene.sceneId + ' -> ' + toScene.sceneId)
148 |
149 | n3.timeline.transition('*', '*', t1)
150 | .transition('timelineScene_3', 'timelineScene_1', t2)
151 | .transition(['timelineScene_3'], ['timelineScene_2', 'timelineScene_4'], t3)
152 |
153 | n3.timeline.switchScene('timelineScene_2')
154 | n3.timeline.switchScene('timelineScene_4')
155 | n3.timeline.switchScene('timelineScene_3')
156 | n3.timeline.switchScene('timelineScene_1')
157 |
158 | n3.timeline.switchScene('timelineScene_3')
159 | n3.timeline.switchScene('timelineScene_2')
160 | n3.timeline.switchScene('timelineScene_1')
161 |
162 | n3.timeline.switchScene('timelineScene_3')
163 | n3.timeline.switchScene('timelineScene_4')
164 | n3.timeline.switchScene('timelineScene_2')
165 |
166 | n3.timeline.switchScene('timelineScene_3')
167 | n3.timeline.switchScene('timelineScene_1')
--------------------------------------------------------------------------------
/test/trigger.test.coffee:
--------------------------------------------------------------------------------
1 | describe "trigger", ->
2 | vis = null
3 |
4 | beforeEach ->
5 | vis = n3.vis('triggerTest')
6 | .state('state_1', ['valid', 'value'])
7 | .state('state_2', [1, 2, 3, 4, 5, 6])
8 | .render(->
9 | console.log('triggerTest render');
10 | )
11 |
12 | it "is equal", ->
13 | t = n3.trigger(vis)
14 | .where('state_1')
15 | .is('value')
16 |
17 | expect(t.evaluate([vis.visId, 'state_1'], 'valid')).toBe false
18 | expect(t.evaluate([vis.visId, 'state_1'], 'value')).toBe true
19 |
20 | it "is not", ->
21 | t = n3.trigger(vis)
22 | .where('state_1')
23 | .not('value')
24 |
25 | expect(t.evaluate([vis.visId, 'state_1'], 'valid')).toBe true
26 | expect(t.evaluate([vis.visId, 'state_1'], 'value')).toBe false
27 |
28 | it "is greater than", ->
29 | t = n3.trigger(vis)
30 | .where('state_2')
31 | .gt(3)
32 |
33 | expect(t.evaluate([vis.visId, 'state_2'], 1)).toBe false
34 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe false
35 | expect(t.evaluate([vis.visId, 'state_2'], 5)).toBe true
36 |
37 | it "is greater than or equal to", ->
38 | t = n3.trigger(vis)
39 | .where('state_2')
40 | .gte(3)
41 |
42 | expect(t.evaluate([vis.visId, 'state_2'], 1)).toBe false
43 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe true
44 | expect(t.evaluate([vis.visId, 'state_2'], 5)).toBe true
45 |
46 | it "is less than", ->
47 | t = n3.trigger(vis)
48 | .where('state_2')
49 | .lt(3)
50 |
51 | expect(t.evaluate([vis.visId, 'state_2'], 1)).toBe true
52 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe false
53 | expect(t.evaluate([vis.visId, 'state_2'], 5)).toBe false
54 |
55 | it "is less than", ->
56 | t = n3.trigger(vis)
57 | .where('state_2')
58 | .lte(3)
59 |
60 | expect(t.evaluate([vis.visId, 'state_2'], 1)).toBe true
61 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe true
62 | expect(t.evaluate([vis.visId, 'state_2'], 5)).toBe false
63 |
64 | it "is and trigger", ->
65 | t = n3.trigger.and(
66 | n3.trigger(vis)
67 | .where('state_1')
68 | .is('value'),
69 |
70 | n3.trigger(vis)
71 | .where('state_2')
72 | .is(3)
73 | )
74 |
75 | vis.state('state_1', 'valid')
76 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe false
77 | expect(t.evaluate([vis.visId, 'state_1'], 'value')).toBe false
78 |
79 | vis.state('state_1', 'value')
80 | expect(t.evaluate([vis.visId, 'state_2'], 4)).toBe false
81 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe true
82 |
83 | t1 = n3.trigger.and(
84 | n3.trigger(vis)
85 | .where('state_1')
86 | .is('value'),
87 |
88 | n3.trigger(vis)
89 | .where('state_2')
90 | .gt(3)
91 | )
92 |
93 | vis.state('state_1', 'valid')
94 | vis.state('state_2', 1)
95 | expect(t1.evaluate([vis.visId, 'state_1'], 'value')).toBe false
96 | expect(t1.evaluate([vis.visId, 'state_2'], 4)).toBe false
97 |
98 | vis.state('state_2', 5)
99 | expect(t1.evaluate([vis.visId, 'state_1'], 'valid')).toBe false
100 | expect(t1.evaluate([vis.visId, 'state_1'], 'value')).toBe true
101 |
102 | it "is or", ->
103 | t = n3.trigger.or(
104 | n3.trigger(vis)
105 | .where('state_1')
106 | .is('value'),
107 |
108 | n3.trigger(vis)
109 | .where('state_2')
110 | .is(3)
111 | )
112 |
113 | expect(t.evaluate([vis.visId, 'state_1'], 'valid')).toBe false
114 | expect(t.evaluate([vis.visId, 'state_1'], 'value')).toBe true
115 | expect(t.evaluate([vis.visId, 'state_2'], 5)).toBe false
116 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe true
117 |
118 | t = n3.trigger.or(
119 | n3.trigger(vis)
120 | .where('state_1')
121 | .is(5),
122 |
123 | n3.trigger(vis)
124 | .where('state_2')
125 | .lt(3)
126 | )
127 |
128 | expect(t.evaluate([vis.visId, 'state_1'], 5)).toBe true
129 | expect(t.evaluate([vis.visId, 'state_2'], 4)).toBe false
130 | expect(t.evaluate([vis.visId, 'state_2'], 5)).toBe false
131 | expect(t.evaluate([vis.visId, 'state_2'], 3)).toBe false
132 | expect(t.evaluate([vis.visId, 'state_2'], 2)).toBe true
133 |
134 | # it "registers and is notified by state change", ->
135 | # t = n3.trigger(vis)
136 | # .where('state_1')
137 | # .is('value')
138 | #
139 | # t1 = n3.trigger(vis)
140 | # .where('state_2')
141 | # .lte(3)
142 | #
143 | # n3.trigger.register(t)
144 | # n3.trigger.register(t1)
145 | #
146 | #
147 | # spyOn(t, 'evaluate')
148 | # spyOn(t1, 'evaluate')
149 | #
150 | # vis.state('state_1', 'valid')
151 | # expect(t.evaluate).toHaveBeenCalledWith('valid')
152 |
--------------------------------------------------------------------------------
/test/vis.test.coffee:
--------------------------------------------------------------------------------
1 | describe "vis", ->
2 | vis = null
3 | vis2 = null
4 |
5 | beforeEach ->
6 | vis = n3.vis('visTest')
7 | vis2 = n3.vis('visTest2')
8 |
9 | it "sets/gets the stage", ->
10 | stage = d3.select('body')
11 | .append('div')
12 | .attr('id', 'stage')
13 |
14 | # Testing if .stage() sets all properties and is chainable
15 | expect(vis.stage('#stage', 100, 200).width()).toBe 100
16 | expect(vis.height()).toBe 200
17 | expect(vis.stage()).toEqual d3.select('#stage')
18 |
19 | # Tests .width() setter/getter/chaining
20 | expect(vis.width(150).height()).toBe 200
21 | expect(vis.width()).toBe 150
22 |
23 | # Tests .height() setter/getter/chaining
24 | expect(vis.height(250).width()).toBe 150
25 | expect(vis.height()).toBe 250
26 |
27 | # Tests that the stage has not been set for any other vis
28 | expect(vis2.width()).toBeUndefined
29 |
30 | it "sets/gets readOnly consts", ->
31 | # Testing if .const() sets and is chainable
32 | expect(vis.const('foo', 'bar').const('foo')).toBe 'bar'
33 |
34 | # Testing to ensure consts are readOnly
35 | expect(vis.const('foo', 'baz').const('foo')).toBe 'bar'
36 |
37 | # Testing setting multiple consts
38 | expect(vis.const('hello', 'world').const('top', 'cat').const('foo')).toBe 'bar'
39 | expect(vis.const('hello')).toBe 'world'
40 | expect(vis.const('top')).toBe 'cat'
41 |
42 | # Testing to ensure consts not set on any other vis
43 | expect(vis2.const('foo')).toBeUndefined
44 | expect(vis2.const('hello')).toBeUndefined
45 | expect(vis2.const('top')).toBeUndefined
46 |
47 | it "sets/gets the data", ->
48 | d = ["do", "re", "mi", "fa", "so"]
49 |
50 | # Testing if .data() sets and is chainable
51 | expect(vis.data(d).data()).toBe d
52 |
53 | # Testing if .data() supports different data types
54 | d1 = {Jagger: "Rock", Elvis: "Roll"}
55 | expect(vis.data(d1).data()).toBe d1
56 |
57 | d2 =
58 | brother:
59 | name: "Max"
60 | age: 11
61 | sister:
62 | name: "Ida"
63 | age: 9
64 |
65 | expect(vis.data(d2).data()).toBe d2
66 |
67 | # Tests that .data is not set for another vis
68 | expect(vis2.data()).toBeUndefined
69 |
70 | it "sets/gets the state", ->
71 | vis.state('state1', ['va1', 'va2'])
72 | .state('state2', ['foo', 'bar', 'hello', 'world'])
73 | .bind('state1', (val) -> console.log("state1 = #{val}"))
74 | .bind('state2', (val) -> console.log("state2 = #{val}"))
75 | .render(->
76 | console.log('hello');
77 | )
78 |
79 | expect(vis.states['state1'].visId).toBe 'visTest'
80 | expect(vis.states['state1'].validValues).toEqual ['va1', 'va2']
81 | expect(vis.states['state2'].validValues).toEqual ['foo', 'bar', 'hello', 'world']
82 |
83 | spyOn(vis, 'renderFn')
84 |
85 | vis.states['state1'].set('va1')
86 | expect(vis.renderFn).toHaveBeenCalled
87 |
88 | vis.state('state2', 'foo')
89 | expect(vis.renderFn).toHaveBeenCalled
90 |
--------------------------------------------------------------------------------
/ui/css/colorpicker.css:
--------------------------------------------------------------------------------
1 | .colorpicker {
2 | width: 356px;
3 | height: 176px;
4 | overflow: hidden;
5 | position: absolute;
6 | background: url(../imgs/colorpicker_background.png);
7 | font-family: Arial, Helvetica, sans-serif;
8 | display: none;
9 | z-index: 10000;
10 | }
11 | .colorpicker_color {
12 | width: 150px;
13 | height: 150px;
14 | left: 14px;
15 | top: 13px;
16 | position: absolute;
17 | background: #f00;
18 | overflow: hidden;
19 | cursor: crosshair;
20 | }
21 | .colorpicker_color div {
22 | position: absolute;
23 | top: 0;
24 | left: 0;
25 | width: 150px;
26 | height: 150px;
27 | background: url(../imgs/colorpicker_overlay.png);
28 | }
29 | .colorpicker_color div div {
30 | position: absolute;
31 | top: 0;
32 | left: 0;
33 | width: 11px;
34 | height: 11px;
35 | overflow: hidden;
36 | background: url(../imgs/colorpicker_select.gif);
37 | margin: -5px 0 0 -5px;
38 | }
39 | .colorpicker_hue {
40 | position: absolute;
41 | top: 13px;
42 | left: 171px;
43 | width: 35px;
44 | height: 150px;
45 | cursor: n-resize;
46 | }
47 | .colorpicker_hue div {
48 | position: absolute;
49 | width: 35px;
50 | height: 9px;
51 | overflow: hidden;
52 | background: url(../imgs/colorpicker_indic.gif) left top;
53 | margin: -4px 0 0 0;
54 | left: 0px;
55 | }
56 | .colorpicker_new_color {
57 | position: absolute;
58 | width: 60px;
59 | height: 30px;
60 | left: 213px;
61 | top: 13px;
62 | background: #f00;
63 | }
64 | .colorpicker_current_color {
65 | position: absolute;
66 | width: 60px;
67 | height: 30px;
68 | left: 283px;
69 | top: 13px;
70 | background: #f00;
71 | }
72 | .colorpicker input {
73 | background-color: transparent;
74 | border: 1px solid transparent;
75 | position: absolute;
76 | font-size: 10px;
77 | font-family: Arial, Helvetica, sans-serif;
78 | color: #898989;
79 | top: 4px;
80 | right: 11px;
81 | text-align: right;
82 | margin: 0;
83 | padding: 0;
84 | height: 11px;
85 | }
86 | .colorpicker_hex {
87 | position: absolute;
88 | width: 72px;
89 | height: 22px;
90 | background: url(../imgs/colorpicker_hex.png) top;
91 | left: 212px;
92 | top: 142px;
93 | }
94 | .colorpicker_hex input {
95 | right: 6px;
96 | }
97 | .colorpicker_field {
98 | height: 22px;
99 | width: 62px;
100 | background-position: top;
101 | position: absolute;
102 | }
103 | .colorpicker_field span {
104 | position: absolute;
105 | width: 12px;
106 | height: 22px;
107 | overflow: hidden;
108 | top: 0;
109 | right: 0;
110 | cursor: n-resize;
111 | }
112 | .colorpicker_rgb_r {
113 | background-image: url(../imgs/colorpicker_rgb_r.png);
114 | top: 52px;
115 | left: 212px;
116 | }
117 | .colorpicker_rgb_g {
118 | background-image: url(../imgs/colorpicker_rgb_g.png);
119 | top: 82px;
120 | left: 212px;
121 | }
122 | .colorpicker_rgb_b {
123 | background-image: url(../imgs/colorpicker_rgb_b.png);
124 | top: 112px;
125 | left: 212px;
126 | }
127 | .colorpicker_hsb_h {
128 | background-image: url(../imgs/colorpicker_hsb_h.png);
129 | top: 52px;
130 | left: 282px;
131 | }
132 | .colorpicker_hsb_s {
133 | background-image: url(../imgs/colorpicker_hsb_s.png);
134 | top: 82px;
135 | left: 282px;
136 | }
137 | .colorpicker_hsb_b {
138 | background-image: url(../imgs/colorpicker_hsb_b.png);
139 | top: 112px;
140 | left: 282px;
141 | }
142 | .colorpicker_submit {
143 | position: absolute;
144 | width: 22px;
145 | height: 22px;
146 | background: url(../imgs/colorpicker_submit.png) top;
147 | left: 322px;
148 | top: 142px;
149 | overflow: hidden;
150 | }
151 | .colorpicker_focus {
152 | background-position: center;
153 | }
154 | .colorpicker_hex.colorpicker_focus {
155 | background-position: bottom;
156 | }
157 | .colorpicker_submit.colorpicker_focus {
158 | background-position: bottom;
159 | }
160 | .colorpicker_slider {
161 | background-position: bottom;
162 | }
163 |
--------------------------------------------------------------------------------
/ui/css/n3-edit.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Verdana, sans-serif;
3 | font-size: 12px;
4 | }
5 |
6 | #n3-ui_visDialog textarea, #n3-ui_exportDialog textarea {
7 | width: 450px;
8 | height: 200px;
9 | font-family: monospace;
10 | }
11 |
12 | .n3-vis_stage {
13 | float: left;
14 | margin: 15px;
15 | background: #fff;
16 | border: 1px solid #333;
17 | }
18 |
19 | #n3-ui_stage {
20 | position: fixed;
21 | top: 0px;
22 | left: 0;
23 | height: 90%;
24 | overflow: auto;
25 | }
26 |
27 | #n3-ui_stage div.hover { outline: 3px solid firebrick; }
28 |
29 | #n3-ui_stage svg { padding: 0px 10px; }
30 |
31 | #n3-ui_stage .draw svg { cursor: crosshair; }
32 |
33 | #n3-ui_stage svg .hover {
34 | stroke: firebrick;
35 | stroke-width: 3;
36 | }
37 |
38 | p.hover { outline: 2px solid firebrick; }
39 |
40 | #n3-ui_stage .infobar, #n3-ui_widget_panel .header {
41 | clear: both;
42 | display: block;
43 | background: #333;
44 | color: #fff;
45 | padding: 5px 10px;
46 | }
47 |
48 | #n3-ui_stage .infobar p {
49 | float: left;
50 | margin: 5px 20px 5px 0;
51 | background: #333;
52 | }
53 |
54 | #n3-ui_bottom_panel {
55 | position: fixed;
56 | bottom: 0;
57 | left: 0;
58 | width: 100%;
59 | padding: 5px;
60 | background: black url(../imgs/ui-bg_inset-soft_25_000000_1x100.png) 50% bottom repeat-x
61 | }
62 |
63 | #n3-ui_bottom_panel .button {
64 | float: right;
65 | margin-right: 15px;
66 | background-color: #444;
67 | background-repeat: no-repeat;
68 | background-position: 5px 50%;
69 | border: 1px solid #ddd;
70 | height: 40px;
71 | padding: 5px 5px 5px 45px;
72 | color: #fff;
73 | cursor: pointer;
74 | }
75 |
76 | #n3-ui_bottom_panel .button-left { float: left !important; }
77 | #n3-ui_bottom_panel .button:hover { background-color: #555; }
78 |
79 | #n3-ui_bottom_panel .new { background-image: url(../imgs/add-large.png);}
80 | #n3-ui_bottom_panel .end { background-image: url(../imgs/accept.png);}
81 | #n3-ui_bottom_panel .play { background-image: url(../imgs/play.png); }
82 | #n3-ui_bottom_panel .export { background-image: url(../imgs/export.png); }
83 | #n3-ui_bottom_panel .widget { background-image: url(../imgs/widget.png); }
84 |
85 | #n3-ui_palette a {
86 | float: left;
87 | margin-left: 30px;
88 | padding: 0 5px;
89 | width: 32px;
90 | height: 40px;
91 | text-indent: -999em;
92 | background-repeat: no-repeat;
93 | background-position: 50% 50%;
94 | }
95 |
96 | #n3-ui_palette a.selected { background-color: #eaf2ff; }
97 | #n3-ui_palette a:hover { opacity: 0.5; }
98 |
99 | #n3-ui_palette a.circle { background-image: url(../imgs/draw-circle.png); }
100 | #n3-ui_palette a.rect { background-image: url(../imgs/draw-rect.png); }
101 | #n3-ui_palette a.line { background-image: url(../imgs/draw-line.png); }
102 | #n3-ui_palette a.text { background-image: url(../imgs/draw-text.png); }
103 |
104 | #n3-ui_widget_panel {
105 | position: fixed;
106 | top: 15px;
107 | right: 330px;
108 | width: 250px;
109 | height: 90%;
110 | overflow: auto;
111 | }
112 |
113 | #n3-ui_widget_panel .widgets {
114 | border: 1px solid #333;
115 | padding: 5px;
116 | font-weight: normal !important;
117 | }
118 |
119 | #n3-ui_side_panel {
120 | position: fixed;
121 | top: 15px;
122 | right: 15px;
123 | width: 300px;
124 | height: 90%;
125 | overflow: auto;
126 | }
127 |
128 | #n3-ui_side_panel .scene, #n3-ui_widget_panel .widgets {
129 | margin-bottom: 10px;
130 | background-color: #ddd;
131 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#bbb));
132 | background-image: -webkit-linear-gradient(top, #ddd, #bbb);
133 | background-image: -moz-linear-gradient(top, #ddd, #bbb);
134 | background-image: -ms-linear-gradient(top, #ddd, #bbb);
135 | background-image: -o-linear-gradient(top, #ddd, #bbb);
136 | background-image: linear-gradient(to bottom, #ddd, #bbb);
137 | font-weight:bold;
138 | color:#333;
139 | border-radius: 0px !important;
140 | }
141 |
142 | #n3-ui_side_panel .scene-header {
143 | background-image: none !important;
144 | padding: 5px;
145 | cursor: move;
146 | border-radius: 0px !important;
147 | color: #fff;
148 | }
149 |
150 | /*.member {
151 | width: 275px;
152 | margin: 0 auto 5px auto;
153 | }
154 | .member-header, .member-content { padding: 5px; }*/
155 | #n3-ui_side_panel .members { padding-left: 0px !important; }
156 |
157 | #n3-ui_side_panel .member {
158 | list-style-type: none !important;
159 | background: none !important;
160 | color: #333 !important;
161 | border: 0 !important;
162 | height: 32px !important;
163 | margin-bottom: 15px !important;
164 | padding: 5px !important;
165 | }
166 |
167 | #n3-ui_side_panel .members .hover { background: #ddd !important; }
168 |
169 | .ui-icon-edit, .ui-icon-plusthick, .ui-icon-minusthick {
170 | float: right;
171 | margin-left: 15px;
172 | cursor: pointer;
173 | }
174 |
175 | .ui-icon-draggable, .ui-icon-trigger, .ui-icon-style, .ui-icon-delete {
176 | display: inline-block !important;
177 | float: left !important;
178 | height: 32px !important;
179 | margin-right: 15px !important;
180 | cursor: pointer !important;
181 | }
182 |
183 | .ui-icon-draggable {
184 | background: url(../imgs/drag-handle.png) no-repeat 0px 7px !important;
185 | cursor: move !important;
186 | }
187 |
188 | .ui-icon-edit { background: url(../imgs/edit.png) no-repeat !important; }
189 | .ui-icon-trigger { background: url(../imgs/trigger.png) no-repeat 0px 7px !important; }
190 | .ui-icon-trigger-empty { background: url(../imgs/trigger-empty.png) no-repeat 0px 7px !important; }
191 | .ui-icon-style { background: url(../imgs/styles.png) no-repeat 0px 7px !important; }
192 | .ui-icon-delete { background: url(../imgs/delete.png) no-repeat 0px 7px !important; }
193 |
194 | /*.state .member-text { background: url(../imgs/state.png) no-repeat 0px 10px !important; }*/
195 | .state .ui-icon-style { background-image: none !important; }
196 |
197 | #n3-ui_side_panel .member-text {
198 | display: inline-block;
199 | float: left;
200 | width: 160px;
201 | height: 30px;
202 | overflow: hidden;
203 | padding-left: 4px;
204 | }
205 |
206 | #n3-ui_side_panel .transitions {
207 | border-top: 1px dashed #666;
208 | padding: 10px 0 0 40px;
209 | }
210 |
211 | #n3-ui_side_panel .transitions .member-text { margin-top: 5px; }
212 |
213 | #n3-ui_triggerDialog { overflow: auto; }
214 |
215 | #n3-ui_triggerDialog textarea {
216 | width: 100%;
217 | height: 100px;
218 | font-family: monospace;
219 | }
220 |
221 | #n3-ui_triggerDialog li {
222 | list-style-type: none;
223 | border-top: 1px solid #444;
224 | }
225 |
226 | #n3-ui_triggerDialog li:nth-child(2) { border-top: 0; }
227 |
228 | #n3-ui_triggerDialog .add_sub_trigger {
229 | text-indent: -999em;
230 | display: inline-block;
231 | margin-left: 20px;
232 | width: 16px;
233 | height: 16px;
234 | background: url(../imgs/add.png) no-repeat;
235 | }
236 |
237 | #n3-ui_triggerDialog .action { border-bottom: 1px solid #666; }
238 |
239 | #n3-ui_newTransition { margin-top: 30px }
240 | #n3-ui_newTransition a {
241 | margin-top: 10px;
242 | padding: 5px 5px 5px 20px;
243 | border: 1px solid #666;
244 | background: url('../imgs/add.png') 0px 4px no-repeat #333;
245 | text-decoration: none;
246 | }
247 |
248 | #n3-ui_stylesDialog p { margin-bottom: 20px; }
249 |
250 | .style_desc {
251 | display: inline-block;
252 | width: 150px;
253 | margin-right: 5px;
254 | }
255 |
256 | #fill_opacity, #stroke_width {
257 | display: inline-block;
258 | width: 150px;
259 | margin-right: 20px;
260 | }
261 |
262 | #fill_color, #stroke_color {
263 | display: inline-block;
264 | width: 16px;
265 | height: 16px;
266 | border: 1px solid #fff;
267 | cursor: pointer;
268 | }
269 |
270 | p.editable:hover { outline: 1px dotted #CCC; }
271 |
272 | #n3-ui_stylesDialog table, #n3-ui_stylesDialog th, #n3-ui_stylesDialog td {
273 | border: 1px solid #444;
274 | border-collapse: collapse;
275 | }
276 |
277 | #n3-ui_stylesDialog th {
278 | padding: 5px;
279 | background: #444;
280 | border: 1px solid #666;
281 | color: #fff;
282 | }
283 |
284 | #n3-ui_stylesDialog td { padding: 5px; }
285 |
286 | #n3-ui_stylesDialog .data_tbl {
287 | max-width: 470px;
288 | max-height: 200px;
289 | overflow: auto;
290 | }
291 |
292 | #n3-ui_stylesDialog .data_tbl tr:nth-child(odd) { background-color: #222; }
293 | #n3-ui_stylesDialog .data_tbl tr:nth-child(even) { background-color: #000; }
294 | #n3-ui_stylesDialog .data_tbl tr.selected { background-color: #a77214; }
295 |
296 | #n3-ui_stylesDialog input[type=number] { width: 50px; }
297 | #n3-ui_stylesDialog input[type=range] {
298 | -webkit-appearance:none;
299 | -moz-apperance:none;
300 | height:4px;
301 | border-radius: 10px;
302 | }
303 |
304 | #n3-ui_stylesDialog a.bind {
305 | text-indent: -999em;
306 | background: url(../imgs/bind_data.png) no-repeat;
307 | display: inline-block;
308 | width: 16px;
309 | height: 16px;
310 | opacity: 0.4;
311 | }
312 |
313 | #n3-ui_stylesDialog a.bound { opacity: 1; }
314 |
315 | .prop_label {
316 | display: inline-block;
317 | width: 75px;
318 | }
--------------------------------------------------------------------------------
/ui/css/n3-play.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #dcfad0;
3 | font-family: Verdana, sans-serif;
4 | font-size: 12px;
5 | }
6 |
7 | .n3-vis_stage {
8 | float: left;
9 | margin: 15px;
10 | background: #fff;
11 | border: 1px solid #ccc;
12 | }
13 |
14 | #n3-ui_stage {
15 | position: fixed;
16 | top: 0px;
17 | left: 0;
18 | height: 90%;
19 | overflow: scroll;
20 | }
21 |
22 | #n3-ui_stage svg { padding: 0px 10px; }
23 |
24 | #n3-ui_widgets {
25 | position: fixed;
26 | top: 0px;
27 | right: 0px;
28 | width: 200px;
29 | }
30 |
31 | #n3-ui_playbar {
32 | position: fixed;
33 | bottom: 0;
34 | left: 0;
35 | width: 100%;
36 | color: #fff;
37 | background: #333;
38 | }
39 |
40 | #n3-ui_playbar ul {
41 | margin: 0;
42 | list-style-type: none;
43 | }
44 |
45 | #n3-ui_playbar li a {
46 | float: left;
47 | padding: 5px 20px;
48 | border-right: 1px solid #dcfad0;
49 | color: #fff;
50 | text-decoration: none;
51 | font-size: 13px;
52 | }
53 |
54 | #n3-ui_playbar a:hover, #n3-ui_playbar a.selected {
55 | background: #dcfad0;
56 | color: #333;
57 | }
--------------------------------------------------------------------------------
/ui/imgs/accept.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/accept.png
--------------------------------------------------------------------------------
/ui/imgs/add-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/add-large.png
--------------------------------------------------------------------------------
/ui/imgs/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/add.png
--------------------------------------------------------------------------------
/ui/imgs/bind_data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/bind_data.png
--------------------------------------------------------------------------------
/ui/imgs/blank.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/blank.gif
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_background.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_hex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_hex.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_hsb_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_hsb_b.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_hsb_h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_hsb_h.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_hsb_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_hsb_s.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_indic.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_indic.gif
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_overlay.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_rgb_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_rgb_b.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_rgb_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_rgb_g.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_rgb_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_rgb_r.png
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_select.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_select.gif
--------------------------------------------------------------------------------
/ui/imgs/colorpicker_submit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/colorpicker_submit.png
--------------------------------------------------------------------------------
/ui/imgs/custom_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_background.png
--------------------------------------------------------------------------------
/ui/imgs/custom_hex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_hex.png
--------------------------------------------------------------------------------
/ui/imgs/custom_hsb_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_hsb_b.png
--------------------------------------------------------------------------------
/ui/imgs/custom_hsb_h.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_hsb_h.png
--------------------------------------------------------------------------------
/ui/imgs/custom_hsb_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_hsb_s.png
--------------------------------------------------------------------------------
/ui/imgs/custom_indic.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_indic.gif
--------------------------------------------------------------------------------
/ui/imgs/custom_rgb_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_rgb_b.png
--------------------------------------------------------------------------------
/ui/imgs/custom_rgb_g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_rgb_g.png
--------------------------------------------------------------------------------
/ui/imgs/custom_rgb_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_rgb_r.png
--------------------------------------------------------------------------------
/ui/imgs/custom_submit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/custom_submit.png
--------------------------------------------------------------------------------
/ui/imgs/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/delete.png
--------------------------------------------------------------------------------
/ui/imgs/drag-handle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/drag-handle.png
--------------------------------------------------------------------------------
/ui/imgs/draw-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/draw-circle.png
--------------------------------------------------------------------------------
/ui/imgs/draw-ellipse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/draw-ellipse.png
--------------------------------------------------------------------------------
/ui/imgs/draw-line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/draw-line.png
--------------------------------------------------------------------------------
/ui/imgs/draw-rect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/draw-rect.png
--------------------------------------------------------------------------------
/ui/imgs/draw-text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/draw-text.png
--------------------------------------------------------------------------------
/ui/imgs/edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/edit.png
--------------------------------------------------------------------------------
/ui/imgs/export.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/export.png
--------------------------------------------------------------------------------
/ui/imgs/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/play.png
--------------------------------------------------------------------------------
/ui/imgs/select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/select.png
--------------------------------------------------------------------------------
/ui/imgs/select2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/select2.png
--------------------------------------------------------------------------------
/ui/imgs/slider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/slider.png
--------------------------------------------------------------------------------
/ui/imgs/state.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/state.png
--------------------------------------------------------------------------------
/ui/imgs/styles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/styles.png
--------------------------------------------------------------------------------
/ui/imgs/trigger-empty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/trigger-empty.png
--------------------------------------------------------------------------------
/ui/imgs/trigger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/trigger.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_flat_0_aaaaaa_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_flat_0_aaaaaa_40x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_flat_30_cccccc_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_flat_30_cccccc_40x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_flat_50_5c5c5c_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_flat_50_5c5c5c_40x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_flat_75_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_flat_75_ffffff_40x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_20_555555_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_20_555555_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_40_0078a3_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_40_0078a3_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_40_ffc73d_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_40_ffc73d_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_55_fbf9ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_55_fbf9ee_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_75_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_75_dadada_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_75_e6e6e6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_75_e6e6e6_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_glass_95_fef1ec_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_glass_95_fef1ec_1x400.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_gloss-wave_25_333333_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_gloss-wave_25_333333_500x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_highlight-soft_75_cccccc_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_highlight-soft_75_cccccc_1x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_highlight-soft_80_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_highlight-soft_80_eeeeee_1x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_inset-soft_25_000000_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_inset-soft_25_000000_1x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-bg_inset-soft_30_f58400_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-bg_inset-soft_30_f58400_1x100.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_2e83ff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_2e83ff_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_454545_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_454545_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_4b8e0b_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_4b8e0b_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_888888_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_888888_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_a83300_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_a83300_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_cccccc_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_cccccc_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_cd0a0a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_cd0a0a_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/ui/imgs/widget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uwdata/ellipsis/288599be9b582924e374f76f6569aaa02e6f592e/ui/imgs/widget.png
--------------------------------------------------------------------------------
/ui/js/d3.min.js:
--------------------------------------------------------------------------------
1 | ../../node_modules/d3/d3.v2.min.js
--------------------------------------------------------------------------------
/ui/js/jquery.chromatable.js:
--------------------------------------------------------------------------------
1 | /*
2 | * File: chromatable.js
3 | * Version: 1.3.0
4 | * CVS: $Id$
5 | * Description: Make a "sticky" header at the top of the table, so it stays put while the table scrolls
6 | * Author: Zachary Siswick
7 | * Created: Thursday 19 November 2009 8:53pm
8 | * Language: Javascript
9 | *
10 | */
11 | (function($){
12 |
13 | $.chromatable = {
14 | // Default options
15 | defaults: {
16 | //specify a pixel dimension, auto, or 100%
17 | width: "900px",
18 | height: "300px",
19 | scrolling: "yes"
20 | }
21 |
22 | };
23 |
24 | $.fn.chromatable = function(options){
25 |
26 | // Extend default options
27 | var options = $.extend({}, $.chromatable.defaults, options);
28 |
29 | return this.each(function(){
30 |
31 | // Add jQuery methods to the element
32 | var $this = $(this);
33 | var $uniqueID = $(this).attr("ID") + ("wrapper");
34 |
35 |
36 | //Add dimentsions from user or default parameters to the DOM elements
37 | $(this).css('width', options.width).addClass("_scrolling");
38 |
39 | $(this).wrap('');
40 |
41 | $(".scrolling_outer").css({'position':'relative'});
42 | $("#"+$uniqueID).css(
43 |
44 | {'border':'1px solid #CCCCCC',
45 | 'overflow-x':'hidden',
46 | 'overflow-y':'auto',
47 | 'padding-right':'17px'
48 | });
49 |
50 | $("#"+$uniqueID).css('height', options.height);
51 | $("#"+$uniqueID).css('width', options.width);
52 |
53 | // clone an exact copy of the scrolling table and add to DOM before the original table
54 | // replace old class with new to differentiate between the two
55 | $(this).before($(this).clone().attr("id", "").addClass("_thead").css(
56 |
57 | {'width' : 'auto',
58 | 'display' : 'block',
59 | 'position':'absolute',
60 | 'border':'none',
61 | 'border-bottom':'1px solid #CCC',
62 | 'top':'1px'
63 | }));
64 |
65 |
66 | // remove all children within the cloned table after the thead element
67 | $('._thead').children('tbody').remove();
68 |
69 |
70 | $(this).each(function( $this ){
71 |
72 | // if the width is auto, we need to remove padding-right on scrolling container
73 |
74 | if (options.width == "100%" || options.width == "auto") {
75 |
76 | $("#"+$uniqueID).css({'padding-right':'0px'});
77 | }
78 |
79 |
80 | if (options.scrolling == "no") {
81 |
82 | $("#"+$uniqueID).before('Expand table ');
83 |
84 | $("#"+$uniqueID).css({'padding-right':'0px'});
85 |
86 | $(".expander").each(
87 |
88 |
89 | function(int){
90 |
91 | $(this).attr("ID", int);
92 |
93 | $( this ).bind ("click",function(){
94 |
95 | $("#"+$uniqueID).css({'height':'auto'});
96 |
97 | $("#"+$uniqueID+" ._thead").remove();
98 |
99 | $(this).remove();
100 |
101 | });
102 | });
103 |
104 |
105 | //this is dependant on the jQuery resizable UI plugin
106 | $("#"+$uniqueID).resizable({ handles: 's' }).css("overflow-y", "hidden");
107 |
108 | }
109 |
110 | });
111 |
112 |
113 | // Get a relative reference to the "sticky header"
114 | $curr = $this.prev();
115 |
116 | // Copy the cell widths across from the original table
117 | $("thead:eq(0)>tr th",this).each( function (i) {
118 |
119 | $("thead:eq(0)>tr th:eq("+i+")", $curr).width( $(this).width());
120 |
121 | });
122 |
123 |
124 | //check to see if the width is set to auto, if not, we don't need to call the resizer function
125 | if (options.width == "100%" || "auto"){
126 |
127 |
128 | // call the resizer function whenever the table width has been adjusted
129 | $(window).resize(function(){
130 |
131 | resizer($this);
132 | });
133 | }
134 | });
135 |
136 | };
137 |
138 | // private function to temporarily hide the header when the browser is resized
139 |
140 | function resizer($this) {
141 |
142 | // Need a relative reference to the "sticky header"
143 | $curr = $this.prev();
144 |
145 | $("thead:eq(0)>tr th", $this).each( function (i) {
146 |
147 | $("thead:eq(0)>tr th:eq("+i+")", $curr).width( $(this).width());
148 |
149 | });
150 |
151 | };
152 |
153 | })(jQuery);
--------------------------------------------------------------------------------
/ui/js/jquery.getPath.js:
--------------------------------------------------------------------------------
1 | jQuery.fn.getPath = function () {
2 | if (this.length != 1) throw 'Requires one element.';
3 |
4 | var path, node = this;
5 |
6 | if(node.attr('id'))
7 | return '#' + node.attr('id');
8 |
9 | while (node.length) {
10 | var realNode = node[0], name = realNode.localName;
11 | if (!name) break;
12 | name = name.toLowerCase();
13 | // Only go up to the visualization's stage element though
14 | // (which definitely have an ID)
15 | // TODO: how to make this work w/non-svg stages?
16 | if(name == 'svg')
17 | return '#' + node.attr('id') + (path ? '>' + path : '');
18 |
19 | var parent = node.parent();
20 |
21 | var siblings = parent.children(name);
22 | if (siblings.length > 1) {
23 | name += ':eq(' + siblings.index(realNode) + ')';
24 | }
25 |
26 | path = name + (path ? '>' + path : '');
27 | node = parent;
28 | }
29 |
30 | return path;
31 | };
--------------------------------------------------------------------------------
/ui/js/jquery.json-2.3.min.js:
--------------------------------------------------------------------------------
1 |
2 | (function($){var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';}
3 | var type=typeof o;if(type==='undefined'){return undefined;}
4 | if(type==='number'||type==='boolean'){return''+o;}
5 | if(type==='string'){return $.quoteString(o);}
6 | if(type==='object'){if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());}
7 | if(o.constructor===Date){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;}
8 | if(day<10){day='0'+day;}
9 | if(hours<10){hours='0'+hours;}
10 | if(minutes<10){minutes='0'+minutes;}
11 | if(seconds<10){seconds='0'+seconds;}
12 | if(milli<100){milli='0'+milli;}
13 | if(milli<10){milli='0'+milli;}
14 | return'"'+year+'-'+month+'-'+day+'T'+
15 | hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
16 | if(o.constructor===Array){var ret=[];for(var i=0;i' +
25 | ' ');
27 | }
28 | }
29 |
30 | function populatePlayBar() {
31 | $('#n3-ui_playbar ul').html('');
32 |
33 | for(var i in sceneOrder) {
34 | var s = sceneOrder[i];
35 | $('#n3-ui_playbar ul').append('' + s + ' ');
36 | }
37 | }
38 |
39 | function switchScene(id) {
40 | $('.selected').removeClass('selected');
41 | $('#n3-ui_' + id).addClass('selected');
42 |
43 | n3.timeline.switchScene(id);
44 | }
--------------------------------------------------------------------------------
/ui/js/n3.js:
--------------------------------------------------------------------------------
1 | ../../n3.js
--------------------------------------------------------------------------------
/ui/play.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Author a Story with N3
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
70 |
71 |
--------------------------------------------------------------------------------