├── .gitignore
├── LICENSE
├── README.md
├── bin
└── build.js
├── index.html
├── index.js
├── jit
├── Examples
│ ├── AreaChart
│ │ ├── example1.html
│ │ └── example1.js
│ ├── BarChart
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ └── example2.js
│ ├── ForceDirected
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ └── example2.js
│ ├── Hypertree
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ ├── example2.js
│ │ ├── example3.html
│ │ └── example3.js
│ ├── Icicle
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ └── example2.js
│ ├── Other
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ ├── example2.js
│ │ ├── example3.html
│ │ └── example3.js
│ ├── PieChart
│ │ ├── example1.html
│ │ └── example1.js
│ ├── RGraph
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ ├── example2.js
│ │ ├── example3.html
│ │ ├── example3.js
│ │ ├── example4.html
│ │ └── example4.js
│ ├── Spacetree
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ ├── example2.js
│ │ ├── example3.html
│ │ ├── example3.js
│ │ ├── example4.html
│ │ ├── example4.js
│ │ ├── example5.html
│ │ └── example5.js
│ ├── Sunburst
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ └── example2.js
│ ├── Treemap
│ │ ├── example1.html
│ │ ├── example1.js
│ │ ├── example2.html
│ │ ├── example2.js
│ │ ├── example3.html
│ │ └── example3.js
│ └── css
│ │ ├── AreaChart.css
│ │ ├── BarChart.css
│ │ ├── ForceDirected.css
│ │ ├── ForceDirected3D.css
│ │ ├── HeatMap.css
│ │ ├── Hypertree.css
│ │ ├── Icicle.css
│ │ ├── Other.css
│ │ ├── PieChart.css
│ │ ├── RGraph.css
│ │ ├── Spacetree.css
│ │ ├── Sunburst.css
│ │ ├── TimeGraph.css
│ │ ├── Treemap.css
│ │ ├── base.css
│ │ ├── col1.png
│ │ ├── col2.png
│ │ └── gradient.png
├── Extras
│ └── excanvas.js
├── jit-yc.js
└── jit.js
├── package.json
├── src
└── js
│ ├── block.js
│ ├── char.js
│ ├── document.js
│ ├── tree-ux.js
│ ├── util.js
│ ├── word.js
│ └── words.js
├── style.css
└── test
└── unit
├── block.spec.js
├── char.spec.js
├── util.spec.js
└── word.spec.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /dist
3 | /coverage
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright yabwe
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/yabwe/words
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules directory are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # words
2 | A humble yet ambitious attempt to build a WYSIWYG editor, backed by JSON, without relying on document.execCommand
3 |
4 | ## Getting Started
5 |
6 | **1)** Pull down the repo
7 |
8 | **2)** Pull down the dependencies
9 |
10 | ```
11 | npm install
12 | ```
13 |
14 | **3)** Start the server
15 |
16 | ```
17 | npm start
18 | ```
19 |
20 | **4)** Load the page
21 |
22 | ```
23 | http://localhost:8088
24 | ```
25 |
26 | **5)** Dance, everybody dance
27 |
28 | ## Bundling JS
29 |
30 | ```
31 | npm run build
32 | ```
33 |
34 | ## Running Unit Tests
35 |
36 | ```
37 | npm test
38 | ```
39 |
40 | ## Running Code Coverage
41 |
42 | ```
43 | npm run coverage
44 | ```
45 |
46 | ## Current JSON Tree Structure
47 |
48 | The current strategy is to represent the state of the editor text via a tree object in JSON
49 |
50 | ### Document
51 |
52 | A **Document** is the top level object and the root of the tree. It represents all of the text within the editor.
53 |
54 | **Document** objects have 2 main properties:
55 |
56 | 1. **blocks**
57 | * Array of all the **Block** objects which are its children. These are loosely tied to block elements in that blocks are always separated by new lines.
58 | 2. **chars**
59 | * Array of all the **Char** objects within the entire editor. These are the leaf-nodes of the data tree.
60 |
61 | ### Block
62 |
63 | A **Block** is an object which represents a chunk of text which is separated by other chunks of text by new lines.
64 |
65 | **Block** objects have 2 main properties:
66 |
67 | 1. **words**
68 | * Array of all the **Word** objects which are its children.
69 | 2. **parent**
70 | * A reference to its parent **Document** object.
71 |
72 | ### Word
73 |
74 | A **Word** is an object which represents a chunk of text which is separated by other chunks of text by spaces (within the same **Block**). All words will contain their ending character, which will either be:
75 | * A Space (' ')
76 | * A Newline ('\n')
77 | * An Empty String ('')
78 | * The last word in the **Document** will have this empty string as a terminator
79 |
80 | **Word** objects have 2 main properties:
81 |
82 | 1. **chars**
83 | * Array of all the **Char** objects which are its children.
84 | 2. **parent**
85 | * A reference to its parent **Block** object.
86 |
87 | ### Char
88 |
89 | A **Char** is an object which represents a single character of text. Currently, this will be where all formatting information will be stored (ie bold, italic, blockquote, etc.).
90 |
91 | **Char** objects will represent every single character within a **Document**. This includes spaces, newlines, and the empty character terminator.
92 |
93 | **Char** objects have 3 main properties:
94 |
95 | 1. **char**
96 | * The character this represents
97 | 2. **props**
98 | * Key-Value pair representing a formatting property and whether it is applied (ie bold, italic, blockquote)
99 | 3. **parent**
100 | * A reference to its parent **Word** object.
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/bin/build.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var fs = require('fs');
3 |
4 | var browserify = require('browserify');
5 |
6 | var fileName = process.env.npm_package_name + '.js';
7 | var srcDir = './src/js';
8 | var distDir = './dist';
9 |
10 | var files = [path.join(srcDir, fileName)];
11 |
12 | if (!fs.existsSync(distDir)){
13 | fs.mkdirSync(distDir);
14 | }
15 |
16 | var b = browserify(files);
17 |
18 | b.bundle().pipe(fs.createWriteStream(path.join(distDir, fileName)));
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | words | demo
6 |
7 |
8 |
9 |
10 |
11 |
Words
12 |
13 | BOLD
14 | ITALIC
15 | UNDER
16 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var connect = require('connect');
2 | var serveStatic = require('serve-static');
3 | connect().use(serveStatic(__dirname)).listen(8088);
--------------------------------------------------------------------------------
/jit/Examples/AreaChart/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AreaChart - Area Chart Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Area Chart Example
30 |
31 |
32 | A static Area Chart example with gradients that displays tooltips when hovering the stacks.
33 | Left-click a Stack to apply a filter to it.
34 | Right-click to restore all stacks.
35 | Click the Update button to update the JSON data.
36 |
37 |
38 |
39 |
Update Data
40 |
Remove Filter
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/jit/Examples/AreaChart/example1.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | var json = {
32 | 'label': ['label A', 'label B', 'label C', 'label D'],
33 | 'values': [
34 | {
35 | 'label': 'date A',
36 | 'values': [20, 40, 15, 5]
37 | },
38 | {
39 | 'label': 'date B',
40 | 'values': [30, 10, 45, 10]
41 | },
42 | {
43 | 'label': 'date E',
44 | 'values': [38, 20, 35, 17]
45 | },
46 | {
47 | 'label': 'date F',
48 | 'values': [58, 10, 35, 32]
49 | },
50 | {
51 | 'label': 'date D',
52 | 'values': [55, 60, 34, 38]
53 | },
54 | {
55 | 'label': 'date C',
56 | 'values': [26, 40, 25, 40]
57 | }]
58 |
59 | };
60 | var json2 = {
61 | 'values': [
62 | {
63 | 'label': 'date A',
64 | 'values': [10, 40, 15, 7]
65 | },
66 | {
67 | 'label': 'date B',
68 | 'values': [30, 40, 45, 9]
69 | },
70 | {
71 | 'label': 'date D',
72 | 'values': [55, 30, 34, 26]
73 | },
74 | {
75 | 'label': 'date C',
76 | 'values': [26, 40, 85, 28]
77 | }]
78 |
79 | };
80 | //end
81 | var infovis = document.getElementById('infovis');
82 | //init AreaChart
83 | var areaChart = new $jit.AreaChart({
84 | //id of the visualization container
85 | injectInto: 'infovis',
86 | //add animations
87 | animate: true,
88 | //separation offsets
89 | Margin: {
90 | top: 5,
91 | left: 5,
92 | right: 5,
93 | bottom: 5
94 | },
95 | labelOffset: 10,
96 | //whether to display sums
97 | showAggregates: true,
98 | //whether to display labels at all
99 | showLabels: true,
100 | //could also be 'stacked'
101 | type: useGradients? 'stacked:gradient' : 'stacked',
102 | //label styling
103 | Label: {
104 | type: labelType, //can be 'Native' or 'HTML'
105 | size: 13,
106 | family: 'Arial',
107 | color: 'white'
108 | },
109 | //enable tips
110 | Tips: {
111 | enable: true,
112 | onShow: function(tip, elem) {
113 | tip.innerHTML = "" + elem.name + " : " + elem.value;
114 | }
115 | },
116 | //add left and right click handlers
117 | filterOnClick: true,
118 | restoreOnRightClick:true
119 | });
120 | //load JSON data.
121 | areaChart.loadJSON(json);
122 | //end
123 | var list = $jit.id('id-list'),
124 | button = $jit.id('update'),
125 | restoreButton = $jit.id('restore');
126 | //update json on click
127 | $jit.util.addEvent(button, 'click', function() {
128 | var util = $jit.util;
129 | if(util.hasClass(button, 'gray')) return;
130 | util.removeClass(button, 'white');
131 | util.addClass(button, 'gray');
132 | areaChart.updateJSON(json2);
133 | });
134 | //restore graph on click
135 | $jit.util.addEvent(restoreButton, 'click', function() {
136 | areaChart.restore();
137 | });
138 | //dynamically add legend to list
139 | var legend = areaChart.getLegend(),
140 | listItems = [];
141 | for(var name in legend) {
142 | listItems.push('
' + name);
144 | }
145 | list.innerHTML = '' + listItems.join(' ') + ' ';
146 | }
147 |
--------------------------------------------------------------------------------
/jit/Examples/BarChart/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BarChart - Bar Chart Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Bar Chart Example
30 |
31 |
32 | A static vertical Bar Chart example with gradients. The Bar Chart displays tooltips when hovering the stacks.
33 | Click the Update button to update the JSON data.
34 |
35 |
36 |
37 |
Update Data
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/jit/Examples/BarChart/example1.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | var json = {
32 | 'label': ['label A', 'label B', 'label C', 'label D'],
33 | 'values': [
34 | {
35 | 'label': 'date A',
36 | 'values': [20, 40, 15, 5]
37 | },
38 | {
39 | 'label': 'date B',
40 | 'values': [30, 10, 45, 10]
41 | },
42 | {
43 | 'label': 'date E',
44 | 'values': [38, 20, 35, 17]
45 | },
46 | {
47 | 'label': 'date F',
48 | 'values': [58, 10, 35, 32]
49 | },
50 | {
51 | 'label': 'date D',
52 | 'values': [55, 60, 34, 38]
53 | },
54 | {
55 | 'label': 'date C',
56 | 'values': [26, 40, 25, 40]
57 | }]
58 |
59 | };
60 | //end
61 | var json2 = {
62 | 'values': [
63 | {
64 | 'label': 'date A',
65 | 'values': [10, 40, 15, 7]
66 | },
67 | {
68 | 'label': 'date B',
69 | 'values': [30, 40, 45, 9]
70 | },
71 | {
72 | 'label': 'date D',
73 | 'values': [55, 30, 34, 26]
74 | },
75 | {
76 | 'label': 'date C',
77 | 'values': [26, 40, 85, 28]
78 | }]
79 |
80 | };
81 | //init BarChart
82 | var barChart = new $jit.BarChart({
83 | //id of the visualization container
84 | injectInto: 'infovis',
85 | //whether to add animations
86 | animate: true,
87 | //horizontal or vertical barcharts
88 | orientation: 'vertical',
89 | //bars separation
90 | barsOffset: 20,
91 | //visualization offset
92 | Margin: {
93 | top:5,
94 | left: 5,
95 | right: 5,
96 | bottom:5
97 | },
98 | //labels offset position
99 | labelOffset: 5,
100 | //bars style
101 | type: useGradients? 'stacked:gradient' : 'stacked',
102 | //whether to show the aggregation of the values
103 | showAggregates:true,
104 | //whether to show the labels for the bars
105 | showLabels:true,
106 | //labels style
107 | Label: {
108 | type: labelType, //Native or HTML
109 | size: 13,
110 | family: 'Arial',
111 | color: 'white'
112 | },
113 | //add tooltips
114 | Tips: {
115 | enable: true,
116 | onShow: function(tip, elem) {
117 | tip.innerHTML = "" + elem.name + " : " + elem.value;
118 | }
119 | }
120 | });
121 | //load JSON data.
122 | barChart.loadJSON(json);
123 | //end
124 | var list = $jit.id('id-list'),
125 | button = $jit.id('update'),
126 | orn = $jit.id('switch-orientation');
127 | //update json on click 'Update Data'
128 | $jit.util.addEvent(button, 'click', function() {
129 | var util = $jit.util;
130 | if(util.hasClass(button, 'gray')) return;
131 | util.removeClass(button, 'white');
132 | util.addClass(button, 'gray');
133 | barChart.updateJSON(json2);
134 | });
135 | //dynamically add legend to list
136 | var legend = barChart.getLegend(),
137 | listItems = [];
138 | for(var name in legend) {
139 | listItems.push('
' + name);
141 | }
142 | list.innerHTML = '' + listItems.join(' ') + ' ';
143 | }
144 |
--------------------------------------------------------------------------------
/jit/Examples/BarChart/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BarChart - Bar Chart Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Bar Chart Example
30 |
31 |
32 | A static horizontal Bar Chart example without gradients. The Bar Chart displays tooltips when hovering the stacks.
33 | Click the Update button to update the JSON data.
34 |
35 |
36 |
37 |
Update Data
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/jit/Examples/BarChart/example2.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | var json = {
32 | 'label': ['label A', 'label B', 'label C', 'label D'],
33 | 'values': [
34 | {
35 | 'label': 'date A',
36 | 'values': [20, 40, 15, 5]
37 | },
38 | {
39 | 'label': 'date B',
40 | 'values': [30, 10, 45, 10]
41 | },
42 | {
43 | 'label': 'date E',
44 | 'values': [38, 20, 35, 17]
45 | },
46 | {
47 | 'label': 'date F',
48 | 'values': [58, 10, 35, 32]
49 | },
50 | {
51 | 'label': 'date D',
52 | 'values': [55, 60, 34, 38]
53 | },
54 | {
55 | 'label': 'date C',
56 | 'values': [26, 40, 25, 40]
57 | }]
58 |
59 | };
60 | //end
61 | var json2 = {
62 | 'values': [
63 | {
64 | 'label': 'date A',
65 | 'values': [10, 40, 15, 7]
66 | },
67 | {
68 | 'label': 'date B',
69 | 'values': [30, 40, 45, 9]
70 | },
71 | {
72 | 'label': 'date D',
73 | 'values': [55, 30, 34, 26]
74 | },
75 | {
76 | 'label': 'date C',
77 | 'values': [26, 40, 85, 28]
78 | }]
79 |
80 | };
81 | //init BarChart
82 | var barChart = new $jit.BarChart({
83 | //id of the visualization container
84 | injectInto: 'infovis',
85 | //whether to add animations
86 | animate: true,
87 | //horizontal or vertical barcharts
88 | orientation: 'horizontal',
89 | //bars separation
90 | barsOffset: 0.5,
91 | //visualization offset
92 | Margin: {
93 | top: 5,
94 | left: 5,
95 | right: 5,
96 | bottom: 5
97 | },
98 | //labels offset position
99 | labelOffset:5,
100 | //bars style
101 | type:'stacked',
102 | //whether to show the aggregation of the values
103 | showAggregates:true,
104 | //whether to show the labels for the bars
105 | showLabels:true,
106 | //label styles
107 | Label: {
108 | type: labelType, //Native or HTML
109 | size: 13,
110 | family: 'Arial',
111 | color: 'white'
112 | },
113 | //tooltip options
114 | Tips: {
115 | enable: true,
116 | onShow: function(tip, elem) {
117 | tip.innerHTML = "" + elem.name + " : " + elem.value;
118 | }
119 | }
120 | });
121 | //load JSON data.
122 | barChart.loadJSON(json);
123 | //end
124 | var list = $jit.id('id-list'),
125 | button = $jit.id('update');
126 | //update json on click 'Update Data'
127 | $jit.util.addEvent(button, 'click', function() {
128 | var util = $jit.util;
129 | if(util.hasClass(button, 'gray')) return;
130 | util.removeClass(button, 'white');
131 | util.addClass(button, 'gray');
132 | barChart.updateJSON(json2);
133 | });
134 | //dynamically add legend to list
135 | var legend = barChart.getLegend(),
136 | listItems = [];
137 | for(var name in legend) {
138 | listItems.push('
' + name);
140 | }
141 | list.innerHTML = '' + listItems.join(' ') + ' ';
142 | }
143 |
--------------------------------------------------------------------------------
/jit/Examples/ForceDirected/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ForceDirected - Force Directed Static Graph
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Force Directed Static Graph
30 |
31 |
32 | A static JSON Graph structure is used as input for this visualization.
33 | You can zoom and pan the visualization by scrolling and dragging .
34 | You can change node positions by dragging the nodes around .
35 | The clicked node's connections are displayed in a relations list in the right column.
36 | The JSON static data is customized to provide different node types, colors and widths.
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/jit/Examples/ForceDirected/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ForceDirected - Graph Operations
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Graph Operations
30 |
31 |
32 | In this (advanced) example a static graph is fed into the visualization.
33 | Custom Animations are triggered when clicking on a node's label or when deleting a node.
34 | Click on a node's label to select a node and its connections.
35 | Click on the 'x' link to delete a node.
36 | You can drag nodes around and zoom and pan , just like you did in the previous
37 | example.
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/jit/Examples/Hypertree/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hypertree - Tree Animation
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Tree Animation
30 |
31 |
32 | A static JSON Tree structure is used as input for this animation.
33 | Clicking on a node should move the tree and center that node.
34 | The centered node's children are displayed in a relations list in the right column.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/jit/Examples/Hypertree/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hypertree - Weighted Graph Animation
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Weighted Graph Animation
30 |
31 |
32 | A static JSON graph structure is used for this animation.
33 | For each JSON node the "$type" and "$dim" parameters set the type of node to be plotted and its dimensions.
34 | Line weights are added programmatically, onBeforePlotLine .
35 | A Back transition is used instead of the linear transition for the animation.
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/Hypertree/example2.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | //By defining properties with the dollar sign ($)
32 | //in nodes and edges we can override the global configuration
33 | //properties for nodes and edges.
34 | //In this case we use "$type" and "$dim" properties to override
35 | //the type of the node to be plotted and its dimension.
36 | var json = [{
37 | "id": "node0",
38 | "name": "node0 name",
39 | "data": {
40 | "$dim": 16.759175934208628,
41 | "some other key": "some other value"
42 | },
43 | "adjacencies": [{
44 | "nodeTo": "node1",
45 | "data": {
46 | "weight": 3
47 | }
48 | }, {
49 | "nodeTo": "node2",
50 | "data": {
51 | "weight": 3
52 | }
53 | }, {
54 | "nodeTo": "node3",
55 | "data": {
56 | "weight": 3
57 | }
58 | }, {
59 | "nodeTo": "node4",
60 | "data": {
61 | "weight": 1
62 | }
63 | }, {
64 | "nodeTo": "node5",
65 | "data": {
66 | "weight": 1
67 | }
68 | }]
69 | }, {
70 | "id": "node1",
71 | "name": "node1 name",
72 | "data": {
73 | "$dim": 13.077119090372014,
74 | "$type": "square",
75 | "some other key": "some other value"
76 | },
77 | "adjacencies": [{
78 | "nodeTo": "node0",
79 | "data": {
80 | "weight": 3
81 | }
82 | }, {
83 | "nodeTo": "node2",
84 | "data": {
85 | "weight": 1
86 | }
87 | }, {
88 | "nodeTo": "node3",
89 | "data": {
90 | "weight": 3
91 | }
92 | }, {
93 | "nodeTo": "node4",
94 | "data": {
95 | "weight": 1
96 | }
97 | }, {
98 | "nodeTo": "node5",
99 | "data": {
100 | "weight": 1
101 | }
102 | }]
103 | }, {
104 | "id": "node2",
105 | "name": "node2 name",
106 | "data": {
107 | "$dim": 24.937383149648717,
108 | "$type": "triangle",
109 | "some other key": "some other value"
110 | },
111 | "adjacencies": [{
112 | "nodeTo": "node0",
113 | "data": {
114 | "weight": 3
115 | }
116 | }, {
117 | "nodeTo": "node1",
118 | "data": {
119 | "weight": 1
120 | }
121 | }, {
122 | "nodeTo": "node3",
123 | "data": {
124 | "weight": 3
125 | }
126 | }, {
127 | "nodeTo": "node4",
128 | "data": {
129 | "weight": 3
130 | }
131 | }, {
132 | "nodeTo": "node5",
133 | "data": {
134 | "weight": 1
135 | }
136 | }]
137 | }, {
138 | "id": "node3",
139 | "name": "node3 name",
140 | "data": {
141 | "$dim": 10.53272740718869,
142 | "some other key": "some other value"
143 | },
144 | "adjacencies": [{
145 | "nodeTo": "node0",
146 | "data": {
147 | "weight": 3
148 | }
149 | }, {
150 | "nodeTo": "node1",
151 | "data": {
152 | "weight": 3
153 | }
154 | }, {
155 | "nodeTo": "node2",
156 | "data": {
157 | "weight": 3
158 | }
159 | }, {
160 | "nodeTo": "node4",
161 | "data": {
162 | "weight": 1
163 | }
164 | }, {
165 | "nodeTo": "node5",
166 | "data": {
167 | "weight": 3
168 | }
169 | }]
170 | }, {
171 | "id": "node4",
172 | "name": "node4 name",
173 | "data": {
174 | "$dim": 5.3754347037767345,
175 | "$type":"triangle",
176 | "some other key": "some other value"
177 | },
178 | "adjacencies": [{
179 | "nodeTo": "node0",
180 | "data": {
181 | "weight": 1
182 | }
183 | }, {
184 | "nodeTo": "node1",
185 | "data": {
186 | "weight": 1
187 | }
188 | }, {
189 | "nodeTo": "node2",
190 | "data": {
191 | "weight": 3
192 | }
193 | }, {
194 | "nodeTo": "node3",
195 | "data": {
196 | "weight": 1
197 | }
198 | }, {
199 | "nodeTo": "node5",
200 | "data": {
201 | "weight": 3
202 | }
203 | }]
204 | }, {
205 | "id": "node5",
206 | "name": "node5 name",
207 | "data": {
208 | "$dim": 32.26403873194912,
209 | "$type": "star",
210 | "some other key": "some other value"
211 | },
212 | "adjacencies": [{
213 | "nodeTo": "node0",
214 | "data": {
215 | "weight": 1
216 | }
217 | }, {
218 | "nodeTo": "node1",
219 | "data": {
220 | "weight": 1
221 | }
222 | }, {
223 | "nodeTo": "node2",
224 | "data": {
225 | "weight": 1
226 | }
227 | }, {
228 | "nodeTo": "node3",
229 | "data": {
230 | "weight": 3
231 | }
232 | }, {
233 | "nodeTo": "node4",
234 | "data": {
235 | "weight": 3
236 | }
237 | }]
238 | }];
239 | //end
240 | //init Hypertree
241 | var ht = new $jit.Hypertree({
242 | //id of the visualization container
243 | injectInto: 'infovis',
244 | //By setting overridable=true,
245 | //Node and Edge global properties can be
246 | //overriden for each node/edge.
247 | Node: {
248 | overridable: true,
249 | 'transform': false,
250 | color: "#f00"
251 | },
252 |
253 | Edge: {
254 | overridable: true,
255 | color: "#088"
256 | },
257 | //calculate nodes offset
258 | offset: 0.2,
259 | //Change the animation transition type
260 | transition: $jit.Trans.Back.easeOut,
261 | //animation duration (in milliseconds)
262 | duration:1000,
263 |
264 | //This method is called right before plotting an
265 | //edge. This method is useful for adding individual
266 | //styles to edges.
267 | onBeforePlotLine: function(adj){
268 | //Set random lineWidth for edges.
269 | if (!adj.data.$lineWidth)
270 | adj.data.$lineWidth = Math.random() * 7 + 1;
271 | },
272 |
273 | onBeforeCompute: function(node){
274 | Log.write("centering");
275 | },
276 | //Attach event handlers on label creation.
277 | onCreateLabel: function(domElement, node){
278 | domElement.innerHTML = node.name;
279 | domElement.style.cursor = "pointer";
280 | domElement.onclick = function () {
281 | ht.onClick(node.id, {
282 | hideLabels: false,
283 | onComplete: function() {
284 | ht.controller.onComplete();
285 | }
286 | });
287 | };
288 | },
289 | //This method is called when moving/placing a label.
290 | //You can add some positioning offsets to the labels here.
291 | onPlaceLabel: function(domElement, node){
292 | var width = domElement.offsetWidth;
293 | var intX = parseInt(domElement.style.left);
294 | intX -= width / 2;
295 | domElement.style.left = intX + 'px';
296 | },
297 |
298 | onComplete: function(){
299 | Log.write("done");
300 |
301 | //Make the relations list shown in the right column.
302 | var node = ht.graph.getClosestNodeToOrigin("current");
303 | var html = "" + node.name + " Connections: ";
304 | html += "";
305 | node.eachAdjacency(function(adj){
306 | var child = adj.nodeTo;
307 | html += "" + child.name + " ";
308 | });
309 | html += " ";
310 | $jit.id('inner-details').innerHTML = html;
311 | }
312 | });
313 | //load JSON graph.
314 | ht.loadJSON(json, 2);
315 | //compute positions and plot
316 | ht.refresh();
317 | //end
318 | ht.controller.onBeforeCompute(ht.graph.getNode(ht.root));
319 | ht.controller.onComplete();
320 | }
321 |
--------------------------------------------------------------------------------
/jit/Examples/Hypertree/example3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hypertree - Graph Operations
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Graph Operations
30 |
31 |
32 | You can do the following operations with the Hypertree
33 | 1.- Removing subtrees or nodes
34 | 2.- Removing edges
35 | 3.- Adding another graph, also called sum
36 | 4.- Morphing (or transforming) the graph into another one
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
Global Options
53 |
54 |
92 |
93 |
1.- Remove Nodes
94 |
95 |
118 |
119 |
2.- Remove Edges
120 |
121 |
144 |
145 |
3.- Add Graph (Sum)
146 |
147 |
169 |
170 |
4.- Morph
171 |
172 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
--------------------------------------------------------------------------------
/jit/Examples/Icicle/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Icicle - Icicle Tree with static JSON data
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Icicle Tree with static JSON data
29 |
30 |
31 |
Some static JSON tree data is fed to this visualization.
32 |
33 | Left click to set a node as root for the visualization.
34 |
35 |
36 | Right click to set the parent node as root for the visualization.
37 |
38 |
39 |
40 |
41 |
Orientation:
42 |
43 | horizontal
44 | vertical
45 |
46 |
47 |
48 | Max levels:
49 |
50 | all
51 | 1
52 | 2
53 | 3
54 | 4
55 | 5
56 |
57 |
58 |
59 |
60 |
61 |
Go to Parent
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
72 |
73 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/jit/Examples/Icicle/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Icicle - Icicle tree with limited levels shown
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Icicle tree with limited levels shown
29 |
30 |
31 |
A static JSON tree representing a file system tree is loaded into
32 | an Icicle Tree.
33 |
34 | Left click to set a node as root for the visualization.
35 |
36 |
37 | Right click to set the parent node as root for the visualization.
38 |
39 |
40 |
41 |
42 |
Orientation:
43 |
44 | horizontal
45 | vertical
46 |
47 |
48 |
49 | Max levels:
50 |
51 | all
52 | 1
53 | 2
54 | 3
55 | 4
56 | 5
57 |
58 |
59 |
60 |
61 |
62 |
Go to Parent
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
74 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/jit/Examples/Other/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Other - Implementing Node Types
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Implementing Node Types
30 |
31 |
32 | In this example some custom node types are created for rendering pie charts with the RGraph.
33 | Multiple instances of the RGraph are created using these node types. (top)
34 | The SpaceTree is loaded with some custom data that individually changes nodes dimensions, making a bar chart (bottom).
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/Other/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Other - Composing Visualizations
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Composing Visualizations
30 |
31 |
32 | In this example a RGraph is composed with another RGraph (for node rendering).
33 | The RGraph used for node rendering implements a custom node type defined in the "Implementing Node Types" example.
34 | This example shows that many visualizations can be composed to create new visualizations.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/Other/example2.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init() {
30 | //init data
31 | var json = {
32 | 'id': 'root',
33 | 'name': 'RGraph( RGraph )',
34 | 'data': {
35 | '$type': 'none'
36 | },
37 | 'children':[
38 | {
39 | 'id':'pie10',
40 | 'name': 'pie1',
41 | 'data': {
42 | '$angularWidth': 20,
43 | '$color': '#f55'
44 | },
45 | 'children': [
46 | {
47 | 'id':'pie100',
48 | 'name': 'pc1',
49 | 'data': {
50 | '$angularWidth': 20,
51 | '$color': '#55f'
52 | },
53 | 'children': []
54 |
55 | },
56 | {
57 | 'id':'pie101',
58 | 'name': 'pc2',
59 | 'data': {
60 | '$angularWidth': 70,
61 | '$color': '#66f'
62 | },
63 | 'children': []
64 |
65 | },
66 | {
67 | 'id':'pie102',
68 | 'name': 'pc3',
69 | 'data': {
70 | '$angularWidth': 10,
71 | '$color': '#77f'
72 | },
73 | 'children': []
74 |
75 | }
76 | ]
77 | },
78 | {
79 | 'id':'pie20',
80 | 'name': 'pie2',
81 | 'data': {
82 | '$angularWidth': 40,
83 | '$color': '#f77'
84 | },
85 | 'children': [
86 | {
87 | 'id':'pie200',
88 | 'name': 'pc1',
89 | 'data': {
90 | '$angularWidth': 40,
91 | '$color': '#88f'
92 | },
93 | 'children': []
94 |
95 | },
96 | {
97 | 'id':'pie201',
98 | 'name': 'pc2',
99 | 'data': {
100 | '$angularWidth': 60,
101 | '$color': '#99f'
102 | },
103 | 'children': []
104 |
105 | }
106 | ]
107 | },
108 | {
109 | 'id':'pie30',
110 | 'name': 'pie3',
111 | 'data': {
112 | '$angularWidth': 10,
113 | '$color': '#f99'
114 | },
115 | 'children': [
116 | {
117 | 'id':'pie300',
118 | 'name': 'pc1',
119 | 'data': {
120 | '$angularWidth': 100,
121 | '$color': '#aaf'
122 | },
123 | 'children': []
124 |
125 | }
126 | ]
127 | }
128 | ]
129 | };
130 | var jsonpie = {
131 | 'id': 'root',
132 | 'name': 'RGraph based Pie Chart',
133 | 'data': {
134 | '$type': 'none'
135 | },
136 | 'children':[
137 | {
138 | 'id':'pie1',
139 | 'name': 'pie1',
140 | 'data': {
141 | '$angularWidth': 20,
142 | '$color': '#f55'
143 | },
144 | 'children': []
145 | },
146 | {
147 | 'id':'pie2',
148 | 'name': 'pie2',
149 | 'data': {
150 | '$angularWidth': 40,
151 | '$color': '#f77'
152 | },
153 | 'children': []
154 | },
155 | {
156 | 'id':'pie3',
157 | 'name': 'pie3',
158 | 'data': {
159 | '$angularWidth': 10,
160 | '$color': '#f99'
161 | },
162 | 'children': []
163 | },
164 | {
165 | 'id':'pie4',
166 | 'name': 'pie4',
167 | 'data': {
168 | '$angularWidth': 30,
169 | '$color': '#fbb'
170 | },
171 | 'children': []
172 | }
173 | ]
174 | };
175 | //end
176 |
177 | //init nodetypes
178 | //Here we implement custom node rendering types for the RGraph
179 | //Using this feature requires some javascript and canvas experience.
180 | $jit.RGraph.Plot.NodeTypes.implement({
181 | //This node type is used for plotting pie-chart slices as nodes
182 | 'nodepie': {
183 | 'render': function(node, canvas) {
184 | var span = node.angleSpan, begin = span.begin, end = span.end;
185 | var polarNode = node.pos.getp(true);
186 | var polar = new $jit.Polar(polarNode.rho, begin);
187 | var p1coord = polar.getc(true);
188 | polar.theta = end;
189 | var p2coord = polar.getc(true);
190 |
191 | var ctx = canvas.getCtx();
192 | ctx.beginPath();
193 | ctx.moveTo(0, 0);
194 | ctx.lineTo(p1coord.x, p1coord.y);
195 | ctx.moveTo(0, 0);
196 | ctx.lineTo(p2coord.x, p2coord.y);
197 | ctx.moveTo(0, 0);
198 | ctx.arc(0, 0, polarNode.rho, begin, end, false);
199 | ctx.fill();
200 | }
201 | },
202 | //Create a new node type that renders an entire RGraph visualization
203 | //as node
204 | 'piechart': {
205 | 'render': function(node, canvas, animating) {
206 | var ctx = canvas.getCtx(), pos = node.pos.getc(true);
207 | ctx.save();
208 | ctx.translate(pos.x, pos.y);
209 | pie.plot();
210 | ctx.restore();
211 | }
212 | }
213 | });
214 | //end
215 |
216 | //init pie
217 | //This RGraph instance will be used as the node for
218 | //another RGraph instance.
219 | var pie = new $jit.RGraph({
220 | 'injectInto': 'infovis',
221 | //Optional: create a background canvas and plot
222 | //concentric circles in it.
223 | 'background': {
224 | CanvasStyles: {
225 | strokeStyle: '#555'
226 | }
227 | },
228 | //Add node/edge styles and set
229 | //overridable=true if you want your
230 | //styles to be individually overriden
231 | Node: {
232 | 'overridable': true,
233 | 'type':'nodepie'
234 | },
235 | Edge: {
236 | 'type':'none'
237 | },
238 | //Parent-children distance
239 | levelDistance: 30,
240 | //Don't create labels in this visualization
241 | withLabels: false,
242 | //Don't clear the entire canvas when plotting
243 | //this visualization
244 | clearCanvas: false
245 | });
246 | //load graph.
247 | pie.loadJSON(jsonpie);
248 | pie.compute();
249 | //end
250 |
251 | //init rgraph
252 | var rgraph = new $jit.RGraph({
253 | useCanvas: pie.canvas,
254 | //Add node/edge styles and set
255 | //overridable=true if you want your
256 | //styles to be individually overriden
257 | Node: {
258 | //set the RGraph rendering function
259 | //as node type
260 | 'type': 'piechart'
261 | },
262 | Edge: {
263 | color: '#772277'
264 | },
265 | //Parent-children distance
266 | levelDistance: 100,
267 | //Duration
268 | duration: 1500,
269 | //Add styles to node labels on label creation
270 | onCreateLabel: function(domElement, node){
271 | domElement.innerHTML = node.name;
272 | var style = domElement.style;
273 | style.fontSize = "0.8em";
274 | style.color = "#fff";
275 | style.cursor = "pointer";
276 | domElement.onclick = function() {
277 | rgraph.onClick(node.id, {
278 | hideLabels: false
279 | });
280 | };
281 | },
282 |
283 | onPlaceLabel: function(domElement, node){
284 | var style = domElement.style;
285 | var left = parseInt(style.left);
286 | var w = domElement.offsetWidth;
287 | style.left = (left - w / 2) + 'px';
288 | style.display = '';
289 | }
290 | });
291 | //load graph.
292 | rgraph.loadJSON(json);
293 | rgraph.refresh();
294 | //end
295 | }
296 |
--------------------------------------------------------------------------------
/jit/Examples/Other/example3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Other - Composing Visualizations 2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Composing Visualizations 2
30 |
31 |
32 | In this example a SpaceTree is composed with a RGraph (for node rendering).
33 | The RGraph used for node rendering implements a custom node type defined in the "Implementing Node Types" example.
34 | This example shows that many visualizations can be composed to create new visualizations.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/Other/example3.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init() {
30 | //init data
31 | var json = {
32 | 'id': 'root',
33 | 'name': 'root',
34 | 'data': {
35 | //'$type': 'none'
36 | },
37 | 'children':[
38 | {
39 | 'id':'pie10',
40 | 'name': 'pie1',
41 | 'data': {
42 | '$angularWidth': 20,
43 | '$color': '#f55'
44 | },
45 | 'children': [
46 | {
47 | 'id':'pie100',
48 | 'name': 'pc1',
49 | 'data': {
50 | '$angularWidth': 20,
51 | '$color': '#55f'
52 | },
53 | 'children': []
54 |
55 | },
56 | {
57 | 'id':'pie101',
58 | 'name': 'pc2',
59 | 'data': {
60 | '$angularWidth': 70,
61 | '$color': '#66f'
62 | },
63 | 'children': []
64 |
65 | },
66 | {
67 | 'id':'pie102',
68 | 'name': 'pc3',
69 | 'data': {
70 | '$angularWidth': 10,
71 | '$color': '#77f'
72 | },
73 | 'children': []
74 |
75 | }
76 | ]
77 | },
78 | {
79 | 'id':'pie20',
80 | 'name': 'pie2',
81 | 'data': {
82 | '$angularWidth': 40,
83 | '$color': '#f77'
84 | },
85 | 'children': [
86 | {
87 | 'id':'pie200',
88 | 'name': 'pc1',
89 | 'data': {
90 | '$angularWidth': 40,
91 | '$color': '#88f'
92 | },
93 | 'children': []
94 |
95 | },
96 | {
97 | 'id':'pie201',
98 | 'name': 'pc2',
99 | 'data': {
100 | '$angularWidth': 60,
101 | '$color': '#99f'
102 | },
103 | 'children': []
104 |
105 | }
106 | ]
107 | },
108 | {
109 | 'id':'pie30',
110 | 'name': 'pie3',
111 | 'data': {
112 | '$angularWidth': 10,
113 | '$color': '#f99'
114 | },
115 | 'children': [
116 | {
117 | 'id':'pie300',
118 | 'name': 'pc1',
119 | 'data': {
120 | '$angularWidth': 100,
121 | '$color': '#aaf'
122 | },
123 | 'children': []
124 |
125 | }
126 | ]
127 | }
128 | ]
129 | };
130 | var jsonpie = {
131 | 'id': 'root',
132 | 'name': 'RGraph based Pie Chart',
133 | 'data': {
134 | '$type': 'none'
135 | },
136 | 'children':[
137 | {
138 | 'id':'pie1',
139 | 'name': 'pie1',
140 | 'data': {
141 | '$angularWidth': 20,
142 | '$color': '#55f'
143 | },
144 | 'children': []
145 | },
146 | {
147 | 'id':'pie2',
148 | 'name': 'pie2',
149 | 'data': {
150 | '$angularWidth': 40,
151 | '$color': '#77f'
152 | },
153 | 'children': []
154 | },
155 | {
156 | 'id':'pie3',
157 | 'name': 'pie3',
158 | 'data': {
159 | '$angularWidth': 10,
160 | '$color': '#99f'
161 | },
162 | 'children': []
163 | },
164 | {
165 | 'id':'pie4',
166 | 'name': 'pie4',
167 | 'data': {
168 | '$angularWidth': 30,
169 | '$color': '#bbf'
170 | },
171 | 'children': []
172 | }
173 | ]
174 | };
175 | //end
176 |
177 | //init nodetypes
178 | //Here we implement custom node rendering types for the RGraph
179 | //Using this feature requires some javascript and canvas experience.
180 | $jit.RGraph.Plot.NodeTypes.implement({
181 | //This node type is used for plotting pie-chart slices as nodes
182 | 'shortnodepie': {
183 | 'render': function(node, canvas) {
184 | var ldist = this.config.levelDistance;
185 | var span = node.angleSpan, begin = span.begin, end = span.end;
186 | var polarNode = node.pos.getp(true);
187 |
188 | var polar = new $jit.Polar(polarNode.rho, begin);
189 | var p1coord = polar.getc(true);
190 |
191 | polar.theta = end;
192 | var p2coord = polar.getc(true);
193 |
194 | polar.rho += ldist;
195 | var p3coord = polar.getc(true);
196 |
197 | polar.theta = begin;
198 | var p4coord = polar.getc(true);
199 |
200 |
201 | var ctx = canvas.getCtx();
202 | ctx.beginPath();
203 | ctx.moveTo(p1coord.x, p1coord.y);
204 | ctx.lineTo(p4coord.x, p4coord.y);
205 | ctx.moveTo(0, 0);
206 | ctx.arc(0, 0, polarNode.rho, begin, end, false);
207 |
208 | ctx.moveTo(p2coord.x, p2coord.y);
209 | ctx.lineTo(p3coord.x, p3coord.y);
210 | ctx.moveTo(0, 0);
211 | ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true);
212 |
213 | ctx.fill();
214 | }
215 | }
216 | });
217 |
218 | $jit.ST.Plot.NodeTypes.implement({
219 | //Create a new node type that renders an entire RGraph visualization
220 | 'piechart': {
221 | 'render': function(node, canvas, animating) {
222 | var ctx = canvas.getCtx(), pos = node.pos.getc(true);
223 | ctx.save();
224 | ctx.translate(pos.x, pos.y);
225 | pie.plot();
226 | ctx.restore();
227 | }
228 | }
229 | });
230 | //end
231 |
232 | //init pie
233 | var pie = new $jit.RGraph({
234 | 'injectInto': 'infovis',
235 | //Add node/edge styles and set
236 | //overridable=true if you want your
237 | //styles to be individually overriden
238 | Node: {
239 | 'overridable': true,
240 | 'type':'shortnodepie'
241 | },
242 | Edge: {
243 | 'type':'none'
244 | },
245 | //Parent-children distance
246 | levelDistance: 15,
247 | //Don't create labels for this visualization
248 | withLabels: false,
249 | //Don't clear the canvas when plotting
250 | clearCanvas: false
251 | });
252 | //load graph.
253 | pie.loadJSON(jsonpie);
254 | pie.compute();
255 | //end
256 |
257 | //init st
258 | var st = new $jit.ST({
259 | useCanvas: pie.canvas,
260 | orientation: 'bottom',
261 | //Add node/edge styles
262 | Node: {
263 | type: 'piechart',
264 | width: 60,
265 | height: 60
266 | },
267 | Edge: {
268 | color: '#999',
269 | type: 'quadratic:begin'
270 | },
271 | //Parent-children distance
272 | levelDistance: 60,
273 |
274 | //Add styles to node labels on label creation
275 | onCreateLabel: function(domElement, node){
276 | //add some styles to the node label
277 | var style = domElement.style;
278 | domElement.id = node.id;
279 | style.color = '#fff';
280 | style.fontSize = '0.8em';
281 | style.textAlign = 'center';
282 | style.width = "60px";
283 | style.height = "24px";
284 | style.paddingTop = "22px";
285 | style.cursor = 'pointer';
286 | domElement.innerHTML = node.name;
287 | domElement.onclick = function() {
288 | st.onClick(node.id, {
289 | Move: {
290 | offsetY: -90
291 | }
292 | });
293 | };
294 | }
295 | });
296 | //load json data
297 | st.loadJSON(json);
298 | //compute node positions and layout
299 | st.compute();
300 | //optional: make a translation of the tree
301 | st.geom.translate(new $jit.Complex(0, 200), "start");
302 | //Emulate a click on the root node.
303 | st.onClick(st.root, {
304 | Move: {
305 | offsetY: -90
306 | }
307 | });
308 | //end
309 | }
310 |
--------------------------------------------------------------------------------
/jit/Examples/PieChart/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PieChart - Pie Chart Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Pie Chart Example
30 |
31 |
32 | A static Pie Chart example with gradients that displays tooltips when hovering the stacks.
33 | Click the Update button to update the JSON data.
34 |
35 |
36 |
37 |
Update Data
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/jit/Examples/PieChart/example1.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | var json = {
32 | 'label': ['label A', 'label B', 'label C', 'label D'],
33 | 'values': [
34 | {
35 | 'label': 'date A',
36 | 'values': [20, 40, 15, 5]
37 | },
38 | {
39 | 'label': 'date B',
40 | 'values': [30, 10, 45, 10]
41 | },
42 | {
43 | 'label': 'date E',
44 | 'values': [38, 20, 35, 17]
45 | },
46 | {
47 | 'label': 'date F',
48 | 'values': [58, 10, 35, 32]
49 | },
50 | {
51 | 'label': 'date D',
52 | 'values': [55, 60, 34, 38]
53 | },
54 | {
55 | 'label': 'date C',
56 | 'values': [26, 40, 25, 40]
57 | }]
58 |
59 | };
60 | //end
61 | var json2 = {
62 | 'values': [
63 | {
64 | 'label': 'date A',
65 | 'values': [10, 40, 15, 7]
66 | },
67 | {
68 | 'label': 'date B',
69 | 'values': [30, 40, 45, 9]
70 | },
71 | {
72 | 'label': 'date D',
73 | 'values': [55, 30, 34, 26]
74 | },
75 | {
76 | 'label': 'date C',
77 | 'values': [26, 40, 85, 28]
78 | }]
79 |
80 | };
81 | //init PieChart
82 | var pieChart = new $jit.PieChart({
83 | //id of the visualization container
84 | injectInto: 'infovis',
85 | //whether to add animations
86 | animate: true,
87 | //offsets
88 | offset: 30,
89 | sliceOffset: 0,
90 | labelOffset: 20,
91 | //slice style
92 | type: useGradients? 'stacked:gradient' : 'stacked',
93 | //whether to show the labels for the slices
94 | showLabels:true,
95 | //resize labels according to
96 | //pie slices values set 7px as
97 | //min label size
98 | resizeLabels: 7,
99 | //label styling
100 | Label: {
101 | type: labelType, //Native or HTML
102 | size: 20,
103 | family: 'Arial',
104 | color: 'white'
105 | },
106 | //enable tips
107 | Tips: {
108 | enable: true,
109 | onShow: function(tip, elem) {
110 | tip.innerHTML = "" + elem.name + " : " + elem.value;
111 | }
112 | }
113 | });
114 | //load JSON data.
115 | pieChart.loadJSON(json);
116 | //end
117 | var list = $jit.id('id-list'),
118 | button = $jit.id('update');
119 | //update json on click
120 | $jit.util.addEvent(button, 'click', function() {
121 | var util = $jit.util;
122 | if(util.hasClass(button, 'gray')) return;
123 | util.removeClass(button, 'white');
124 | util.addClass(button, 'gray');
125 | pieChart.updateJSON(json2);
126 | });
127 | //dynamically add legend to list
128 | var legend = pieChart.getLegend(),
129 | listItems = [];
130 | for(var name in legend) {
131 | listItems.push('
' + name);
133 | }
134 | list.innerHTML = '' + listItems.join(' ') + ' ';
135 | }
136 |
--------------------------------------------------------------------------------
/jit/Examples/RGraph/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RGraph - Tree Animation
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Tree Animation
30 |
31 |
32 | A static JSON Tree structure is used as input for this visualization.
33 | Click on a node to move the tree and center that node.
34 | The centered node's children are displayed in a relations list in the right column.
35 | Use the mouse wheel to zoom and drag and drop the canvas to pan.
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/RGraph/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RGraph - Weighted Graph Animation
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Weighted Graph Animation
30 |
31 |
32 | A static JSON graph structure is used for this animation.
33 | For each JSON node/edge the properties prefixed with the dollar sign ($) set the type of node/edge to be plotted, its style and its dimensions.
34 | Line weights are added programmatically, onBeforePlotLine .
35 | An Elastic transition is used instead of the linear transition for the animation.
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/RGraph/example2.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | //If a node in this JSON structure
32 | //has the "$type" or "$dim" parameters
33 | //defined it will override the "type" and
34 | //"dim" parameters globally defined in the
35 | //RGraph constructor.
36 | var json = [{
37 | "id": "node0",
38 | "name": "node0 name",
39 | "data": {
40 | "$dim": 16.759175934208628,
41 | "some other key": "some other value"
42 | },
43 | "adjacencies": [{
44 | "nodeTo": "node1",
45 | "data": {
46 | "weight": 3
47 | }
48 | }, {
49 | "nodeTo": "node2",
50 | "data": {
51 | "weight": 3
52 | }
53 | }, {
54 | "nodeTo": "node3",
55 | "data": {
56 | "weight": 3
57 | }
58 | }, {
59 | "nodeTo": "node4",
60 | "data": {
61 | "$type":"arrow",
62 | "$color":"#dd99dd",
63 | "$dim":25,
64 | "weight": 1
65 | }
66 | }, {
67 | "nodeTo": "node5",
68 | "data": {
69 | "weight": 1
70 | }
71 | }]
72 | }, {
73 | "id": "node1",
74 | "name": "node1 name",
75 | "data": {
76 | "$dim": 13.077119090372014,
77 | "$type": "square",
78 | "some other key": "some other value"
79 | },
80 | "adjacencies": [{
81 | "nodeTo": "node0",
82 | "data": {
83 | "weight": 3
84 | }
85 | }, {
86 | "nodeTo": "node2",
87 | "data": {
88 | "weight": 1
89 | }
90 | }, {
91 | "nodeTo": "node3",
92 | "data": {
93 | "weight": 3
94 | }
95 | }, {
96 | "nodeTo": "node4",
97 | "data": {
98 | "weight": 1
99 | }
100 | }, {
101 | "nodeTo": "node5",
102 | "data": {
103 | "weight": 1
104 | }
105 | }]
106 | }, {
107 | "id": "node2",
108 | "name": "node2 name",
109 | "data": {
110 | "$dim": 24.937383149648717,
111 | "$type": "triangle",
112 | "some other key": "some other value"
113 | },
114 | "adjacencies": [{
115 | "nodeTo": "node0",
116 | "data": {
117 | "weight": 3
118 | }
119 | }, {
120 | "nodeTo": "node1",
121 | "data": {
122 | "weight": 1
123 | }
124 | }, {
125 | "nodeTo": "node3",
126 | "data": {
127 | "weight": 3
128 | }
129 | }, {
130 | "nodeTo": "node4",
131 | "data": {
132 | "weight": 3
133 | }
134 | }, {
135 | "nodeTo": "node5",
136 | "data": {
137 | "weight": 1
138 | }
139 | }]
140 | }, {
141 | "id": "node3",
142 | "name": "node3 name",
143 | "data": {
144 | "$dim": 10.53272740718869,
145 | "some other key": "some other value"
146 | },
147 | "adjacencies": [{
148 | "nodeTo": "node0",
149 | "data": {
150 | "weight": 3
151 | }
152 | }, {
153 | "nodeTo": "node1",
154 | "data": {
155 | "weight": 3
156 | }
157 | }, {
158 | "nodeTo": "node2",
159 | "data": {
160 | "weight": 3
161 | }
162 | }, {
163 | "nodeTo": "node4",
164 | "data": {
165 | "$type":"arrow",
166 | "$direction": ["node4", "node3"],
167 | "$dim":25,
168 | "$color":"#dd99dd",
169 | "weight": 1
170 | }
171 | }, {
172 | "nodeTo": "node5",
173 | "data": {
174 | "weight": 3
175 | }
176 | }]
177 | }, {
178 | "id": "node4",
179 | "name": "node4 name",
180 | "data": {
181 | "$dim": 5.3754347037767345,
182 | "$type":"triangle",
183 | "some other key": "some other value"
184 | },
185 | "adjacencies": [{
186 | "nodeTo": "node0",
187 | "data": {
188 | "weight": 1
189 | }
190 | }, {
191 | "nodeTo": "node1",
192 | "data": {
193 | "weight": 1
194 | }
195 | }, {
196 | "nodeTo": "node2",
197 | "data": {
198 | "weight": 3
199 | }
200 | }, {
201 | "nodeTo": "node3",
202 | "data": {
203 | "weight": 1
204 | }
205 | }, {
206 | "nodeTo": "node5",
207 | "data": {
208 | "weight": 3
209 | }
210 | }]
211 | }, {
212 | "id": "node5",
213 | "name": "node5 name",
214 | "data": {
215 | "$dim": 32.26403873194912,
216 | "$type": "star",
217 | "some other key": "some other value"
218 | },
219 | "adjacencies": [{
220 | "nodeTo": "node0",
221 | "data": {
222 | "weight": 1
223 | }
224 | }, {
225 | "nodeTo": "node1",
226 | "data": {
227 | "weight": 1
228 | }
229 | }, {
230 | "nodeTo": "node2",
231 | "data": {
232 | "weight": 1
233 | }
234 | }, {
235 | "nodeTo": "node3",
236 | "data": {
237 | "weight": 3
238 | }
239 | }, {
240 | "nodeTo": "node4",
241 | "data": {
242 | "weight": 3
243 | }
244 | }]
245 | }];
246 | //end
247 | //init RGraph
248 | var rgraph = new $jit.RGraph({
249 | 'injectInto': 'infovis',
250 | //Optional: Add a background canvas
251 | //that draws some concentric circles.
252 | 'background': {
253 | 'CanvasStyles': {
254 | 'strokeStyle': '#555',
255 | 'shadowBlur': 50,
256 | 'shadowColor': '#ccc'
257 | }
258 | },
259 | //Nodes and Edges parameters
260 | //can be overridden if defined in
261 | //the JSON input data.
262 | //This way we can define different node
263 | //types individually.
264 | Node: {
265 | 'overridable': true,
266 | 'color': '#cc0000'
267 | },
268 | Edge: {
269 | 'overridable': true,
270 | 'color': '#cccc00'
271 | },
272 | //Set polar interpolation.
273 | //Default's linear.
274 | interpolation: 'polar',
275 | //Change the transition effect from linear
276 | //to elastic.
277 | transition: $jit.Trans.Elastic.easeOut,
278 | //Change other animation parameters.
279 | duration:3500,
280 | fps: 30,
281 | //Change father-child distance.
282 | levelDistance: 200,
283 | //This method is called right before plotting
284 | //an edge. This method is useful to change edge styles
285 | //individually.
286 | onBeforePlotLine: function(adj){
287 | //Add some random lineWidth to each edge.
288 | if (!adj.data.$lineWidth)
289 | adj.data.$lineWidth = Math.random() * 5 + 1;
290 | },
291 |
292 | onBeforeCompute: function(node){
293 | Log.write("centering " + node.name + "...");
294 |
295 | //Make right column relations list.
296 | var html = "" + node.name + " Connections: ";
297 | html += "";
298 | node.eachAdjacency(function(adj){
299 | var child = adj.nodeTo;
300 | html += "" + child.name + " ";
301 | });
302 | html += " ";
303 | $jit.id('inner-details').innerHTML = html;
304 | },
305 | //Add node click handler and some styles.
306 | //This method is called only once for each node/label crated.
307 | onCreateLabel: function(domElement, node){
308 | domElement.innerHTML = node.name;
309 | domElement.onclick = function () {
310 | rgraph.onClick(node.id, {
311 | hideLabels: false,
312 | onComplete: function() {
313 | Log.write("done");
314 | }
315 | });
316 | };
317 | var style = domElement.style;
318 | style.cursor = 'pointer';
319 | style.fontSize = "0.8em";
320 | style.color = "#fff";
321 | },
322 | //This method is called when rendering/moving a label.
323 | //This is method is useful to make some last minute changes
324 | //to node labels like adding some position offset.
325 | onPlaceLabel: function(domElement, node){
326 | var style = domElement.style;
327 | var left = parseInt(style.left);
328 | var w = domElement.offsetWidth;
329 | style.left = (left - w / 2) + 'px';
330 | }
331 | });
332 | //load graph.
333 | rgraph.loadJSON(json, 1);
334 |
335 | //compute positions and plot
336 | rgraph.refresh();
337 | //end
338 | rgraph.controller.onBeforeCompute(rgraph.graph.getNode(rgraph.root));
339 | Log.write('done');
340 |
341 | }
342 |
--------------------------------------------------------------------------------
/jit/Examples/RGraph/example3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RGraph - Graph Operations
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Graph Operations
30 |
31 |
32 | You can do the following operations with the RGraph
33 | 1.- Removing subtrees or nodes
34 | 2.- Removing edges
35 | 3.- Adding another graph, also called sum
36 | 4.- Morphing (or transforming) the graph into another one
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
52 |
Global Options
53 |
54 |
92 |
93 |
1.- Remove Nodes
94 |
95 |
118 |
119 |
2.- Remove Edges
120 |
121 |
144 |
145 |
3.- Add Graph (Sum)
146 |
147 |
169 |
170 |
4.- Morph
171 |
172 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
--------------------------------------------------------------------------------
/jit/Examples/RGraph/example4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RGraph - Node Events
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Node Events
30 |
31 |
32 | This example shows how to add node events to the visualization.
33 | This example uses native canvas text for drawing the labels.
34 | Drag and drop nodes around.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/Spacetree/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spacetree - Tree Animation
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Tree Animation
30 |
31 |
32 | A static JSON Tree structure is used as input for this animation.
33 | Click on a node to select it.
34 | You can select the tree orientation by changing the select box in the right column.
35 | You can change the selection mode from Normal selection (i.e. center the selected node) to
36 | Set as Root .
37 | Drag and Drop the canvas to do some panning.
38 | Leaves color depend on the number of children they actually have.
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
Tree Orientation
55 |
89 |
90 |
Selection Mode
91 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/jit/Examples/Spacetree/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spacetree - SpaceTree with on-demand nodes
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | SpaceTree with on-demand nodes
30 |
31 |
32 | This example shows how you can use the request controller method to create a SpaceTree with on demand nodes
33 | The basic JSON Tree structure is cloned and appended on demand on each node to create an infinite large SpaceTree
34 | You can select the tree orientation by changing the select box in the right column.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
Change Tree Orientation
51 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/jit/Examples/Spacetree/example3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spacetree - Add/Remove Subtrees
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Add/Remove Subtrees
30 |
31 |
32 | This example shows how to add/remove subtrees with the SpaceTree.
33 | Add a subtree by clicking on the Add button located in the right column.
34 | Remove a subtree by clicking on a red colored node
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
Add Subtrees
51 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/jit/Examples/Spacetree/example4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spacetree - MultiTree
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | MultiTree
30 |
31 |
32 | A static JSON Tree structure is used as input for this animation.
33 | By setting the specific orientation for nodes we can create a multitree structure.
34 | Nodes and Edges are styled with canvas specific styles like shadows.
35 | Click on a node to select it.
36 | You can change the selection mode from Normal selection (i.e. center the selected node) to
37 | Set as Root .
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
Selection Mode
54 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/jit/Examples/Spacetree/example5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spacetree - Style Animations
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Style Animations
30 |
31 |
32 | This Advanced Example shows how Node, Edge, Label and Canvas specific style animations can be triggered for this
33 | visualization.
34 | Select the styles to be animated in the right column and hit the Morph Styles button. This will
35 | set random values for these properties and animate them.
36 | Click on Restore Styles to set the default styles.
37 | Other styles like alpha and shadows can also be triggered.
38 | This example also implements a custom node rendering function for Stroke + Fill rectangles.
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
53 |
54 |
Actions
55 |
Morph Styles
56 |
Restore Styles
57 |
58 |
Node Styles
59 |
109 |
110 |
Edge Styles
111 |
137 |
138 |
Label Styles
139 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/jit/Examples/Sunburst/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Sunburst - Connected Sunburst
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Connected Sunburst
30 |
31 |
32 | A static JSON Graph structure is used as input for this visualization.
33 | This example shows how properties such as color, height, angular width and line width
34 | can be customized per node and per edge in the JSON structure.
35 | Left click to select a node and show its relations.
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/jit/Examples/Sunburst/example1.js:
--------------------------------------------------------------------------------
1 | var labelType, useGradients, nativeTextSupport, animate;
2 |
3 | (function() {
4 | var ua = navigator.userAgent,
5 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
6 | typeOfCanvas = typeof HTMLCanvasElement,
7 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
8 | textSupport = nativeCanvasSupport
9 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
10 | //I'm setting this based on the fact that ExCanvas provides text support for IE
11 | //and that as of today iPhone/iPad current text support is lame
12 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
13 | nativeTextSupport = labelType == 'Native';
14 | useGradients = nativeCanvasSupport;
15 | animate = !(iStuff || !nativeCanvasSupport);
16 | })();
17 |
18 | var Log = {
19 | elem: false,
20 | write: function(text){
21 | if (!this.elem)
22 | this.elem = document.getElementById('log');
23 | this.elem.innerHTML = text;
24 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
25 | }
26 | };
27 |
28 |
29 | function init(){
30 | //init data
31 | var json = [
32 | //"root" node is invisible
33 | {
34 | "id": "node0",
35 | "name": "",
36 | "data": {
37 | "$type": "none"
38 | },
39 | "adjacencies": [
40 | {
41 | "nodeTo": "node1",
42 | "data": {
43 | '$type': 'none'
44 | }
45 | }, {
46 | "nodeTo": "node2",
47 | "data": {
48 | '$type': 'none'
49 | }
50 | }, {
51 | "nodeTo": "node3",
52 | "data": {
53 | '$type': 'none'
54 | }
55 | }, {
56 | "nodeTo": "node4",
57 | "data": {
58 | "$type": "none"
59 | }
60 | }, {
61 | "nodeTo": "node5",
62 | "data": {
63 | "$type": "none"
64 | }
65 | }, {
66 | "nodeTo": "node6",
67 | "data": {
68 | "$type": "none"
69 | }
70 | }, {
71 | "nodeTo": "node7",
72 | "data": {
73 | "$type": "none"
74 | }
75 | }, {
76 | "nodeTo": "node8",
77 | "data": {
78 | "$type": "none"
79 | }
80 | }, {
81 | "nodeTo": "node9",
82 | "data": {
83 | "$type": "none"
84 | }
85 | }, {
86 | "nodeTo": "node10",
87 | "data": {
88 | "$type": "none"
89 | }
90 | }
91 | ]
92 | }, {
93 | "id": "node1",
94 | "name": "node 1",
95 | "data": {
96 | "$angularWidth": 13.00,
97 | "$color": "#33a",
98 | "$height": 70
99 | },
100 | "adjacencies": [
101 | {
102 | "nodeTo": "node3",
103 | "data": {
104 | "$color": "#ddaacc",
105 | "$lineWidth": 4
106 | }
107 | }, {
108 | "nodeTo": "node5",
109 | "data": {
110 | "$color": "#ccffdd",
111 | "$lineWidth": 4
112 | }
113 | }, {
114 | "nodeTo": "node7",
115 | "data": {
116 | "$color": "#dd99dd",
117 | "$lineWidth": 4
118 | }
119 | }, {
120 | "nodeTo": "node8",
121 | "data": {
122 | "$color": "#dd99dd",
123 | "$lineWidth": 4
124 | }
125 | }, {
126 | "nodeTo": "node10",
127 | "data": {
128 | "$color": "#ddaacc",
129 | "$lineWidth": 4
130 | }
131 | }
132 | ]
133 | }, {
134 | "id": "node2",
135 | "name": "node 2",
136 | "data": {
137 | "$angularWidth": 24.90,
138 | "$color": "#55b",
139 | "$height": 73
140 | },
141 | "adjacencies": [
142 | "node8", "node9", "node10"
143 | ]
144 | }, {
145 | "id": "node3",
146 | "name": "node 3",
147 | "data": {
148 | "$angularWidth": 10.50,
149 | "$color": "#77c",
150 | "$height": 75
151 | },
152 | "adjacencies": [
153 | "node8", "node9", "node10"
154 | ]
155 | }, {
156 | "id": "node4",
157 | "name": "node 4",
158 | "data": {
159 | "$angularWidth": 5.40,
160 | "$color": "#99d",
161 | "$height": 75
162 | },
163 | "adjacencies": [
164 | "node8", "node9", "node10"
165 | ]
166 | }, {
167 | "id": "node5",
168 | "name": "node 5",
169 | "data": {
170 | "$angularWidth": 32.26,
171 | "$color": "#aae",
172 | "$height": 80
173 | },
174 | "adjacencies": [
175 | "node8", "node9", "node10"
176 | ]
177 | }, {
178 | "id": "node6",
179 | "name": "node 6",
180 | "data": {
181 | "$angularWidth": 24.90,
182 | "$color": "#bf0",
183 | "$height": 85
184 | },
185 | "adjacencies": [
186 | "node8", "node9", "node10"
187 | ]
188 | }, {
189 | "id": "node7",
190 | "name": "node 7",
191 | "data": {
192 | "$angularWidth": 14.90,
193 | "$color": "#cf5",
194 | "$height": 85
195 | },
196 | "adjacencies": [
197 | "node8", "node9", "node10"
198 | ]
199 | }, {
200 | "id": "node8",
201 | "name": "node 8",
202 | "data": {
203 | "$angularWidth": 34.90,
204 | "$color": "#dfa",
205 | "$height": 80
206 | },
207 | "adjacencies": [
208 | "node9", "node10"
209 | ]
210 | }, {
211 | "id": "node9",
212 | "name": "node 9",
213 | "data": {
214 | "$angularWidth": 42.90,
215 | "$color": "#CCC",
216 | "$height": 75
217 | },
218 | "adjacencies": [
219 | "node10"
220 | ]
221 | }, {
222 | "id": "node10",
223 | "name": "node 10",
224 | "data": {
225 | "$angularWidth": 100.90,
226 | "$color": "#C37",
227 | "$height": 70
228 | },
229 | "adjacencies": []
230 | }
231 | ];
232 | //end
233 | //init Sunburst
234 | var sb = new $jit.Sunburst({
235 | //id container for the visualization
236 | injectInto: 'infovis',
237 | //Change node and edge styles such as
238 | //color, width, lineWidth and edge types
239 | Node: {
240 | overridable: true,
241 | type: useGradients? 'gradient-multipie' : 'multipie'
242 | },
243 | Edge: {
244 | overridable: true,
245 | type: 'hyperline',
246 | lineWidth: 2,
247 | color: '#777'
248 | },
249 | //Draw canvas text. Can also be
250 | //'HTML' or 'SVG' to draw DOM labels
251 | Label: {
252 | type: nativeTextSupport? 'Native' : 'SVG'
253 | },
254 | //Add animations when hovering and clicking nodes
255 | NodeStyles: {
256 | enable: true,
257 | type: 'Native',
258 | stylesClick: {
259 | 'color': '#33dddd'
260 | },
261 | stylesHover: {
262 | 'color': '#dd3333'
263 | },
264 | duration: 700
265 | },
266 | Events: {
267 | enable: true,
268 | type: 'Native',
269 | //List node connections onClick
270 | onClick: function(node, eventInfo, e){
271 | if (!node) return;
272 | var html = "" + node.name + " connections ", ans = [];
273 | node.eachAdjacency(function(adj){
274 | // if on the same level i.e siblings
275 | if (adj.nodeTo._depth == node._depth) {
276 | ans.push(adj.nodeTo.name);
277 | }
278 | });
279 | $jit.id('inner-details').innerHTML = html + ans.join(" ") + " ";
280 | }
281 | },
282 | levelDistance: 190,
283 | // Only used when Label type is 'HTML' or 'SVG'
284 | // Add text to the labels.
285 | // This method is only triggered on label creation
286 | onCreateLabel: function(domElement, node){
287 | var labels = sb.config.Label.type;
288 | if (labels === 'HTML') {
289 | domElement.innerHTML = node.name;
290 | } else if (labels === 'SVG') {
291 | domElement.firstChild.appendChild(document.createTextNode(node.name));
292 | }
293 | },
294 | // Only used when Label type is 'HTML' or 'SVG'
295 | // Change node styles when labels are placed
296 | // or moved.
297 | onPlaceLabel: function(domElement, node){
298 | var labels = sb.config.Label.type;
299 | if (labels === 'SVG') {
300 | var fch = domElement.firstChild;
301 | var style = fch.style;
302 | style.display = '';
303 | style.cursor = 'pointer';
304 | style.fontSize = "0.8em";
305 | fch.setAttribute('fill', "#fff");
306 | } else if (labels === 'HTML') {
307 | var style = domElement.style;
308 | style.display = '';
309 | style.cursor = 'pointer';
310 | if (node._depth <= 1) {
311 | style.fontSize = "0.8em";
312 | style.color = "#ddd";
313 | }
314 | var left = parseInt(style.left);
315 | var w = domElement.offsetWidth;
316 | style.left = (left - w / 2) + 'px';
317 | }
318 | }
319 | });
320 | // load JSON data.
321 | sb.loadJSON(json);
322 | // compute positions and plot.
323 | sb.refresh();
324 | //end
325 | }
326 |
--------------------------------------------------------------------------------
/jit/Examples/Sunburst/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Sunburst - Sunburst of a Directory Tree
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Sunburst of a Directory Tree
30 |
31 |
32 | A static JSON Tree structure is used as input for this visualization.
33 | Tips are used to describe the file size and its last modified date.
34 | Left click to rotate the Sunburst to the selected node and see its details.
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/jit/Examples/Treemap/example1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Treemap - Animated Squarified, SliceAndDice and Strip TreeMaps
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Animated Squarified, SliceAndDice and Strip TreeMaps
30 |
31 |
32 | In this example a static JSON tree is loaded into a Squarified Treemap.
33 | Left click to set a node as root for the visualization.
34 | Right click to set the parent node as root for the visualization.
35 | You can choose a different tiling algorithm below:
36 |
37 |
38 |
39 |
40 |
67 |
68 |
Go to Parent
69 |
70 |
71 |
72 |
73 |
74 |
77 |
78 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/jit/Examples/Treemap/example2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Treemap - TreeMap with on-demand nodes
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | TreeMap with on-demand nodes
30 |
31 |
32 | This example shows how you can use the request controller method to create a TreeMap with on demand nodes
33 | This example makes use of native Canvas text and shadows, but can be easily adapted to use HTML like the other examples.
34 | There should be only one level shown at a time.
35 | Clicking on a band should show a new TreeMap with its most listened albums.
36 |
37 |
38 |
39 |
66 |
67 |
Go to Parent
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/jit/Examples/Treemap/example3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Treemap - Cushion TreeMaps
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Cushion TreeMaps
30 |
31 |
32 | In this example a static JSON tree is loaded into a Cushion Treemap.
33 | Left click to set a node as root for the visualization.
34 | Right click to set the parent node as root for the visualization.
35 | You can choose a different tiling algorithm below:
36 |
37 |
38 |
39 |
40 |
67 |
68 |
Go to Parent
69 |
70 |
71 |
72 |
73 |
74 |
77 |
78 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/jit/Examples/css/AreaChart.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display: none;
3 | }
4 |
5 | #center-container {
6 | width:800px;
7 | }
8 |
9 | #infovis {
10 | width:800px;
11 | }
12 |
13 | #id-list {
14 | background-color:#EEEEEE;
15 | border:1px solid #CCCCCC;
16 | margin:10px 20px 0 20px;
17 | padding:5px;
18 | text-align:left;
19 | text-indent:2px;
20 | }
21 |
22 | #id-list li {
23 | list-style: none;
24 | margin-bottom:3px;
25 |
26 | }
27 |
28 | .query-color {
29 | border:1px solid #999999;
30 | float:left;
31 | height:10px;
32 | margin:3px 3px 0 0;
33 | width:10px;
34 | }
35 |
36 | #update, #restore {
37 | text-align: center;
38 | width: 100px;
39 | margin:10px 35px;
40 | }
41 |
42 | .button {
43 | display: inline-block;
44 | outline: none;
45 | cursor: pointer;
46 | text-align: center;
47 | text-decoration: none;
48 | font: 14px / 100% Arial, Helvetica, sans-serif;
49 | padding: 0.5em 1em 0.55em;
50 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
51 | -webkit-border-radius: 0.5em;
52 | -moz-border-radius: 0.5em;
53 | border-radius: 0.5em;
54 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
55 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
56 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
57 | }
58 |
59 | .button:hover {
60 | text-decoration: none;
61 | }
62 |
63 | .button:active {
64 | position: relative;
65 | top: 1px;
66 | }
67 |
68 | /* gray */
69 | .gray {
70 | color: #e9e9e9;
71 | border: solid 1px #555;
72 | background: #6e6e6e;
73 | background: -webkit-gradient(linear, left top, left bottom, from(#888), to(#575757));
74 | background: -moz-linear-gradient(top, #888, #575757);
75 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888888', endColorstr='#575757');
76 | }
77 |
78 | .gray:hover {
79 | background: #616161;
80 | background: -webkit-gradient(linear, left top, left bottom, from(#757575), to(#4b4b4b));
81 | background: -moz-linear-gradient(top, #757575, #4b4b4b);
82 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#757575', endColorstr='#4b4b4b');
83 | }
84 |
85 | .gray:active {
86 | color: #afafaf;
87 | background: -webkit-gradient(linear, left top, left bottom, from(#575757), to(#888));
88 | background: -moz-linear-gradient(top, #575757, #888);
89 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#575757', endColorstr='#888888');
90 | }
91 |
92 | /* white */
93 | .white {
94 | color: #606060;
95 | border: solid 1px #b7b7b7;
96 | background: #fff;
97 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
98 | background: -moz-linear-gradient(top, #fff, #ededed);
99 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
100 | }
101 |
102 | .white:hover {
103 | background: #ededed;
104 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
105 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
106 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
107 | }
108 |
109 | .white:active {
110 | color: #999;
111 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
112 | background: -moz-linear-gradient(top, #ededed, #fff);
113 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
114 | }
115 |
--------------------------------------------------------------------------------
/jit/Examples/css/BarChart.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display: none;
3 | }
4 |
5 | #center-container {
6 | width:800px;
7 | }
8 |
9 | #infovis {
10 | width:800px;
11 | }
12 |
13 | #id-list {
14 | background-color:#EEEEEE;
15 | border:1px solid #CCCCCC;
16 | margin:10px 20px 0 20px;
17 | padding:5px;
18 | text-align:left;
19 | text-indent:2px;
20 | }
21 |
22 | #id-list li {
23 | list-style: none;
24 | margin-bottom:3px;
25 |
26 | }
27 |
28 | .query-color {
29 | border:1px solid #999999;
30 | float:left;
31 | height:10px;
32 | margin:3px 3px 0 0;
33 | width:10px;
34 | }
35 |
36 | #update {
37 | margin:10px 40px;
38 | }
39 |
40 | .button {
41 | display: inline-block;
42 | outline: none;
43 | cursor: pointer;
44 | text-align: center;
45 | text-decoration: none;
46 | font: 14px / 100% Arial, Helvetica, sans-serif;
47 | padding: 0.5em 1em 0.55em;
48 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
49 | -webkit-border-radius: 0.5em;
50 | -moz-border-radius: 0.5em;
51 | border-radius: 0.5em;
52 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
53 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
54 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
55 | }
56 |
57 | .button:hover {
58 | text-decoration: none;
59 | }
60 |
61 | .button:active {
62 | position: relative;
63 | top: 1px;
64 | }
65 |
66 | /* gray */
67 | .gray {
68 | color: #e9e9e9;
69 | border: solid 1px #555;
70 | background: #6e6e6e;
71 | background: -webkit-gradient(linear, left top, left bottom, from(#888), to(#575757));
72 | background: -moz-linear-gradient(top, #888, #575757);
73 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888888', endColorstr='#575757');
74 | }
75 |
76 | .gray:hover {
77 | background: #616161;
78 | background: -webkit-gradient(linear, left top, left bottom, from(#757575), to(#4b4b4b));
79 | background: -moz-linear-gradient(top, #757575, #4b4b4b);
80 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#757575', endColorstr='#4b4b4b');
81 | }
82 |
83 | .gray:active {
84 | color: #afafaf;
85 | background: -webkit-gradient(linear, left top, left bottom, from(#575757), to(#888));
86 | background: -moz-linear-gradient(top, #575757, #888);
87 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#575757', endColorstr='#888888');
88 | }
89 |
90 | /* white */
91 | .white {
92 | color: #606060;
93 | border: solid 1px #b7b7b7;
94 | background: #fff;
95 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
96 | background: -moz-linear-gradient(top, #fff, #ededed);
97 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
98 | }
99 |
100 | .white:hover {
101 | background: #ededed;
102 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
103 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
104 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
105 | }
106 |
107 | .white:active {
108 | color: #999;
109 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
110 | background: -moz-linear-gradient(top, #ededed, #fff);
111 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
112 | }
113 |
--------------------------------------------------------------------------------
/jit/Examples/css/ForceDirected.css:
--------------------------------------------------------------------------------
1 | #inner-details {
2 | font-size:12px;
3 | }
4 |
5 | span.close {
6 | color:#FF5555;
7 | cursor:pointer;
8 | font-weight:bold;
9 | margin-left:3px;
10 | }
11 |
12 | span.name {
13 | cursor: pointer;
14 | }
15 |
16 | /*TOOLTIPS*/
17 | .tip {
18 | text-align: left;
19 | width:auto;
20 | max-width:500px;
21 | }
22 |
23 | .tip-title {
24 | font-size: 11px;
25 | text-align:center;
26 | margin-bottom:2px;
27 | }
28 |
--------------------------------------------------------------------------------
/jit/Examples/css/ForceDirected3D.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display: none;
3 | }
4 |
5 | #center-container {
6 | width:800px;
7 | background: #efefef;
8 | }
9 |
10 | #infovis {
11 | width:800px;
12 | }
--------------------------------------------------------------------------------
/jit/Examples/css/HeatMap.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yabwe/words/65b81a28d84339e53f8379a79164a39a3573904d/jit/Examples/css/HeatMap.css
--------------------------------------------------------------------------------
/jit/Examples/css/Hypertree.css:
--------------------------------------------------------------------------------
1 | #infovis-canvaswidget {
2 | margin:25px 0 0 25px;
3 | }
--------------------------------------------------------------------------------
/jit/Examples/css/Icicle.css:
--------------------------------------------------------------------------------
1 | #update {
2 | margin:10px 40px;
3 | }
4 |
5 | .button {
6 | display: inline-block;
7 | outline: none;
8 | cursor: pointer;
9 | text-align: center;
10 | text-decoration: none;
11 | font: 14px / 100% Arial, Helvetica, sans-serif;
12 | padding: 0.5em 1em 0.55em;
13 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
14 | -webkit-border-radius: 0.5em;
15 | -moz-border-radius: 0.5em;
16 | border-radius: 0.5em;
17 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
18 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
19 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
20 | }
21 |
22 | .button:hover {
23 | text-decoration: none;
24 | }
25 |
26 | .button:active {
27 | position: relative;
28 | top: 1px;
29 | }
30 |
31 | /* white */
32 | .white {
33 | color: #606060;
34 | border: solid 1px #b7b7b7;
35 | background: #fff;
36 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
37 | background: -moz-linear-gradient(top, #fff, #ededed);
38 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
39 | }
40 |
41 | .white:hover {
42 | background: #ededed;
43 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
44 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
45 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
46 | }
47 |
48 | .white:active {
49 | color: #999;
50 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
51 | background: -moz-linear-gradient(top, #ededed, #fff);
52 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
53 | }
54 |
55 |
56 | .tip {
57 | text-align: left;
58 | width:auto;
59 | max-width:500px;
60 | }
61 |
62 | .tip-title {
63 | font-size: 11px;
64 | text-align:center;
65 | margin-bottom:2px;
66 | }
67 |
68 | #right-container {
69 | display: none;
70 | }
71 |
72 | #center-container {
73 | width:800px;
74 | }
75 |
76 | #infovis {
77 | width:800px;
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/jit/Examples/css/Other.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display:none;
3 | }
4 |
5 | #infovis {
6 | width:800px;
7 | background-color:#1a1a1a;
8 | }
9 |
--------------------------------------------------------------------------------
/jit/Examples/css/PieChart.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display: none;
3 | }
4 |
5 | #center-container {
6 | width:800px;
7 | }
8 |
9 | #infovis {
10 | width:800px;
11 | }
12 |
13 | #id-list {
14 | background-color:#EEEEEE;
15 | border:1px solid #CCCCCC;
16 | margin:10px 20px 0 20px;
17 | padding:5px;
18 | text-align:left;
19 | text-indent:2px;
20 | }
21 |
22 | #id-list li {
23 | list-style: none;
24 | margin-bottom:3px;
25 |
26 | }
27 |
28 | .query-color {
29 | border:1px solid #999999;
30 | float:left;
31 | height:10px;
32 | margin:3px 3px 0 0;
33 | width:10px;
34 | }
35 |
36 | #update {
37 | margin:10px 40px;
38 | }
39 |
40 | .button {
41 | display: inline-block;
42 | outline: none;
43 | cursor: pointer;
44 | text-align: center;
45 | text-decoration: none;
46 | font: 14px / 100% Arial, Helvetica, sans-serif;
47 | padding: 0.5em 1em 0.55em;
48 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
49 | -webkit-border-radius: 0.5em;
50 | -moz-border-radius: 0.5em;
51 | border-radius: 0.5em;
52 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
53 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
54 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
55 | }
56 |
57 | .button:hover {
58 | text-decoration: none;
59 | }
60 |
61 | .button:active {
62 | position: relative;
63 | top: 1px;
64 | }
65 |
66 | /* gray */
67 | .gray {
68 | color: #e9e9e9;
69 | border: solid 1px #555;
70 | background: #6e6e6e;
71 | background: -webkit-gradient(linear, left top, left bottom, from(#888), to(#575757));
72 | background: -moz-linear-gradient(top, #888, #575757);
73 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888888', endColorstr='#575757');
74 | }
75 |
76 | .gray:hover {
77 | background: #616161;
78 | background: -webkit-gradient(linear, left top, left bottom, from(#757575), to(#4b4b4b));
79 | background: -moz-linear-gradient(top, #757575, #4b4b4b);
80 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#757575', endColorstr='#4b4b4b');
81 | }
82 |
83 | .gray:active {
84 | color: #afafaf;
85 | background: -webkit-gradient(linear, left top, left bottom, from(#575757), to(#888));
86 | background: -moz-linear-gradient(top, #575757, #888);
87 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#575757', endColorstr='#888888');
88 | }
89 |
90 | /* white */
91 | .white {
92 | color: #606060;
93 | border: solid 1px #b7b7b7;
94 | background: #fff;
95 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
96 | background: -moz-linear-gradient(top, #fff, #ededed);
97 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
98 | }
99 |
100 | .white:hover {
101 | background: #ededed;
102 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
103 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
104 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
105 | }
106 |
107 | .white:active {
108 | color: #999;
109 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
110 | background: -moz-linear-gradient(top, #ededed, #fff);
111 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
112 | }
113 |
--------------------------------------------------------------------------------
/jit/Examples/css/RGraph.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yabwe/words/65b81a28d84339e53f8379a79164a39a3573904d/jit/Examples/css/RGraph.css
--------------------------------------------------------------------------------
/jit/Examples/css/Spacetree.css:
--------------------------------------------------------------------------------
1 | .jit-autoadjust-label {
2 | padding: 15px;
3 | }
4 |
5 | #update, #restore {
6 | text-align: center;
7 | width: 100px;
8 | margin:0px 35px 10px 35px;
9 | }
10 |
11 | .button {
12 | display: inline-block;
13 | outline: none;
14 | cursor: pointer;
15 | text-align: center;
16 | text-decoration: none;
17 | font: 14px / 100% Arial, Helvetica, sans-serif;
18 | padding: 0.5em 1em 0.55em;
19 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
20 | -webkit-border-radius: 0.5em;
21 | -moz-border-radius: 0.5em;
22 | border-radius: 0.5em;
23 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
24 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
25 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
26 | }
27 |
28 | .button:hover {
29 | text-decoration: none;
30 | }
31 |
32 | .button:active {
33 | position: relative;
34 | top: 1px;
35 | }
36 |
37 | /* white */
38 | .white {
39 | color: #606060;
40 | border: solid 1px #b7b7b7;
41 | background: #fff;
42 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
43 | background: -moz-linear-gradient(top, #fff, #ededed);
44 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
45 | }
46 |
47 | .white:hover {
48 | background: #ededed;
49 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
50 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
51 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
52 | }
53 |
54 | .white:active {
55 | color: #999;
56 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
57 | background: -moz-linear-gradient(top, #ededed, #fff);
58 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
59 | }
60 |
--------------------------------------------------------------------------------
/jit/Examples/css/Sunburst.css:
--------------------------------------------------------------------------------
1 | /*TOOLTIPS*/
2 | #inner-details {
3 | font-size:12px;
4 | }
5 |
6 | .tip {
7 | text-align: left;
8 | width:auto;
9 | max-width:500px;
10 | }
11 |
12 | .tip-title {
13 | font-size: 11px;
14 | text-align:center;
15 | margin-bottom:2px;
16 | }
17 |
18 | pre {
19 | background-color:#EEEEEE;
20 | border:1px solid #CCCCCC;
21 | font-size:10px;
22 | margin:5px auto;
23 | padding:5px;
24 | width:170px;
25 |
26 | white-space: pre-wrap;
27 | white-space: -moz-pre-wrap;
28 | white-space: -webkit-pre-wrap;
29 | white-space: -pre-wrap;
30 | white-space: -o-pre-wrap;
31 | word-wrap: break-word;
32 | }
--------------------------------------------------------------------------------
/jit/Examples/css/TimeGraph.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display: none;
3 | }
4 |
5 | #center-container {
6 | width:800px;
7 | }
8 |
9 | #infovis {
10 | width:800px;
11 | /*height: 250px;*/
12 | }
13 |
14 | #id-list {
15 | background-color:#EEEEEE;
16 | border:1px solid #CCCCCC;
17 | margin:10px 20px 0 20px;
18 | padding:5px;
19 | text-align:left;
20 | text-indent:2px;
21 | }
22 |
23 | #id-list li {
24 | list-style: none;
25 | margin-bottom:3px;
26 |
27 | }
28 |
29 | .query-color {
30 | border:1px solid #999999;
31 | float:left;
32 | height:10px;
33 | margin:3px 3px 0 0;
34 | width:10px;
35 | }
36 |
37 | #update {
38 | margin:10px 40px;
39 | }
40 |
41 | .button {
42 | display: inline-block;
43 | outline: none;
44 | cursor: pointer;
45 | text-align: center;
46 | text-decoration: none;
47 | font: 14px / 100% Arial, Helvetica, sans-serif;
48 | padding: 0.5em 1em 0.55em;
49 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
50 | -webkit-border-radius: 0.5em;
51 | -moz-border-radius: 0.5em;
52 | border-radius: 0.5em;
53 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
54 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
55 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
56 | }
57 |
58 | .button:hover {
59 | text-decoration: none;
60 | }
61 |
62 | .button:active {
63 | position: relative;
64 | top: 1px;
65 | }
66 |
67 | /* gray */
68 | .gray {
69 | color: #e9e9e9;
70 | border: solid 1px #555;
71 | background: #6e6e6e;
72 | background: -webkit-gradient(linear, left top, left bottom, from(#888), to(#575757));
73 | background: -moz-linear-gradient(top, #888, #575757);
74 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888888', endColorstr='#575757');
75 | }
76 |
77 | .gray:hover {
78 | background: #616161;
79 | background: -webkit-gradient(linear, left top, left bottom, from(#757575), to(#4b4b4b));
80 | background: -moz-linear-gradient(top, #757575, #4b4b4b);
81 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#757575', endColorstr='#4b4b4b');
82 | }
83 |
84 | .gray:active {
85 | color: #afafaf;
86 | background: -webkit-gradient(linear, left top, left bottom, from(#575757), to(#888));
87 | background: -moz-linear-gradient(top, #575757, #888);
88 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#575757', endColorstr='#888888');
89 | }
90 |
91 | /* white */
92 | .white {
93 | color: #606060;
94 | border: solid 1px #b7b7b7;
95 | background: #fff;
96 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
97 | background: -moz-linear-gradient(top, #fff, #ededed);
98 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
99 | }
100 |
101 | .white:hover {
102 | background: #ededed;
103 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
104 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
105 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
106 | }
107 |
108 | .white:active {
109 | color: #999;
110 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
111 | background: -moz-linear-gradient(top, #ededed, #fff);
112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
113 | }
114 |
--------------------------------------------------------------------------------
/jit/Examples/css/Treemap.css:
--------------------------------------------------------------------------------
1 | #right-container {
2 | display: none;
3 | }
4 |
5 | #center-container {
6 | width:800px;
7 | }
8 |
9 | #infovis {
10 | width:800px;
11 | }
12 |
13 | .node {
14 | color:#fff;
15 | font-size:9px;
16 | overflow:hidden;
17 | cursor:pointer;
18 | /*
19 | text-shadow:2px 2px 5px #000;
20 | -o-text-shadow:2px 2px 5px #000;
21 | -webkit-text-shadow:2px 2px 5px #000;
22 | -moz-text-shadow:2px 2px 5px #000;
23 | */
24 | }
25 |
26 | /*TOOLTIPS*/
27 | .tip {
28 | color: #fff;
29 | width: 139px;
30 | background-color: black;
31 | opacity:0.9;
32 | filter:alpha(opacity=90);
33 | font-size:10px;
34 | font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
35 | padding:7px;
36 | }
37 |
38 | .album {
39 | width:100px;
40 | margin:3px;
41 | }
42 |
43 | #id-list {
44 | background-color:#EEEEEE;
45 | border:1px solid #CCCCCC;
46 | margin:10px 20px 0 20px;
47 | padding:5px;
48 | text-align:left;
49 | text-indent:2px;
50 | }
51 |
52 | #id-list table {
53 | margin-top:2px;
54 | }
55 |
56 | #back {
57 | margin:10px 40px;
58 | }
59 |
60 | .button {
61 | display: inline-block;
62 | outline: none;
63 | cursor: pointer;
64 | text-align: center;
65 | text-decoration: none;
66 | font: 14px / 100% Arial, Helvetica, sans-serif;
67 | padding: 0.5em 1em 0.55em;
68 | text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
69 | -webkit-border-radius: 0.5em;
70 | -moz-border-radius: 0.5em;
71 | border-radius: 0.5em;
72 | -webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
73 | -moz-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
74 | box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
75 | }
76 |
77 | .button:hover {
78 | text-decoration: none;
79 | }
80 |
81 | .button:active {
82 | position: relative;
83 | top: 1px;
84 | }
85 |
86 | /* white */
87 | .white {
88 | color: #606060;
89 | border: solid 1px #b7b7b7;
90 | background: #fff;
91 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed));
92 | background: -moz-linear-gradient(top, #fff, #ededed);
93 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed');
94 | }
95 |
96 | .white:hover {
97 | background: #ededed;
98 | background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc));
99 | background: -moz-linear-gradient(top, #fff, #dcdcdc);
100 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc');
101 | }
102 |
103 | .white:active {
104 | color: #999;
105 | background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff));
106 | background: -moz-linear-gradient(top, #ededed, #fff);
107 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff');
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/jit/Examples/css/base.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin:0;
3 | padding:0;
4 | font-family: "Lucida Grande", Verdana;
5 | font-size: 0.9em;
6 | text-align: center;
7 | background-color:#F2F2F2;
8 | }
9 |
10 | input, select {
11 | font-size:0.9em;
12 | }
13 |
14 | table {
15 | margin-top:-10px;
16 | margin-left:7px;
17 | }
18 |
19 | h4 {
20 | font-size:1.1em;
21 | text-decoration:none;
22 | font-weight:normal;
23 | color:#23A4FF;
24 | }
25 |
26 | a {
27 | color:#23A4FF;
28 | }
29 |
30 | #container {
31 | width: 1000px;
32 | height: 600px;
33 | margin:0 auto;
34 | position:relative;
35 | }
36 |
37 | #left-container,
38 | #right-container,
39 | #center-container {
40 | height:600px;
41 | position:absolute;
42 | top:0;
43 | }
44 |
45 | #left-container, #right-container {
46 | width:200px;
47 | color:#686c70;
48 | text-align: left;
49 | overflow: auto;
50 | background-color:#fff;
51 | background-repeat:no-repeat;
52 | border-bottom:1px solid #ddd;
53 | }
54 |
55 | #left-container {
56 | left:0;
57 | background-image:url('col2.png');
58 | background-position:center right;
59 | border-left:1px solid #ddd;
60 |
61 | }
62 |
63 | #right-container {
64 | right:0;
65 | background-image:url('col1.png');
66 | background-position:center left;
67 | border-right:1px solid #ddd;
68 | }
69 |
70 | #right-container h4{
71 | text-indent:8px;
72 | }
73 |
74 | #center-container {
75 | width:600px;
76 | left:200px;
77 | background-color:#1a1a1a;
78 | color:#ccc;
79 | }
80 |
81 | .text {
82 | margin: 7px;
83 | }
84 |
85 | #inner-details {
86 | font-size:0.8em;
87 | list-style:none;
88 | margin:7px;
89 | }
90 |
91 | #log {
92 | position:absolute;
93 | top:10px;
94 | font-size:1.0em;
95 | font-weight:bold;
96 | color:#23A4FF;
97 | }
98 |
99 |
100 | #infovis {
101 | position:relative;
102 | width:600px;
103 | height:600px;
104 | margin:auto;
105 | overflow:hidden;
106 | }
107 |
108 | /*TOOLTIPS*/
109 | .tip {
110 | color: #111;
111 | width: 139px;
112 | background-color: white;
113 | border:1px solid #ccc;
114 | -moz-box-shadow:#555 2px 2px 8px;
115 | -webkit-box-shadow:#555 2px 2px 8px;
116 | -o-box-shadow:#555 2px 2px 8px;
117 | box-shadow:#555 2px 2px 8px;
118 | opacity:0.9;
119 | filter:alpha(opacity=90);
120 | font-size:10px;
121 | font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
122 | padding:7px;
123 | }
--------------------------------------------------------------------------------
/jit/Examples/css/col1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yabwe/words/65b81a28d84339e53f8379a79164a39a3573904d/jit/Examples/css/col1.png
--------------------------------------------------------------------------------
/jit/Examples/css/col2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yabwe/words/65b81a28d84339e53f8379a79164a39a3573904d/jit/Examples/css/col2.png
--------------------------------------------------------------------------------
/jit/Examples/css/gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yabwe/words/65b81a28d84339e53f8379a79164a39a3573904d/jit/Examples/css/gradient.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "words",
3 | "version": "0.0.0",
4 | "description": "Words",
5 | "main": "index.html",
6 | "scripts": {
7 | "start": "npm run test && npm run build && node index.js",
8 | "build": "node bin/build.js",
9 | "test": "mocha test/unit/*.js",
10 | "coverage": "istanbul cover node_modules/mocha/bin/_mocha test/unit/*.js"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "http://github.com/yabwe/words"
15 | },
16 | "author": "Nate Mielnik",
17 | "license": "MIT",
18 | "devDependencies": {
19 | "browserify": "^13.0.0",
20 | "chai": "^3.5.0",
21 | "connect": "^3.4.0",
22 | "istanbul": "^0.4.2",
23 | "mocha": "^2.4.5",
24 | "serve-static": "^1.10.0",
25 | "sinon": "^1.17.3",
26 | "sinon-chai": "^2.8.0"
27 | },
28 | "dependencies": {
29 | "diff": "1.4.0"
30 | },
31 | "bugs": {
32 | "url": "https://github.com/yabwe/words/issues"
33 | },
34 | "homepage": "http://github.com/yabwe/words"
35 | }
36 |
--------------------------------------------------------------------------------
/src/js/block.js:
--------------------------------------------------------------------------------
1 | var Util = require('./util');
2 | var Word = require('./word');
3 | var Char = require('./char');
4 |
5 | /*
6 | * A Block is an object which represents a chunk of text which is separated by other chunks of text by new lines.
7 | *
8 | * Block objects have 2 main properties:
9 | *
10 | * 1. words
11 | * - Array of all the Word objects which are its children.
12 | * 2. parent
13 | * - A reference to its parent Document object.
14 | */
15 | var Block = function (words, parent, type) {
16 | this.parent = parent;
17 |
18 | if (!words || !words.length) {
19 | this.words = [new Word([new Char('')], this)];
20 | } else {
21 | this.words = words;
22 | this.words.forEach(function (word) {
23 | word.parent = this;
24 | }, this);
25 | }
26 |
27 | if (type) {
28 | this.type = type;
29 | }
30 | }
31 |
32 | Block.prototype = {
33 | type: 'p',
34 |
35 | /* merge(block)
36 | *
37 | * Merge the provided block into this block
38 | */
39 | merge: function (block) {
40 | var first = true;
41 | while(block.getWords().length) {
42 | // Remove the word from the previous block and update its parent reference
43 | var nextWord = block.removeWord(block.getFirstWord());
44 | nextWord.parent = this;
45 |
46 | // If this is the first word we're merging in, we need to attempt to merge the words together.
47 | // If there's a space in there, word.merge() accounts for it
48 | if (first) {
49 | this.getLastWord().merge(nextWord);
50 | first = false;
51 | } else {
52 | this.words.push(nextWord);
53 | }
54 | }
55 | },
56 |
57 | /* insertAfter(refWord, word)
58 | *
59 | * Insert a single Word object into this list
60 | * of words, after the provided reference Word (refWord)
61 | *
62 | * If refWord doesn't exist or isn't found, the word
63 | * is added to the end
64 | */
65 | insertAfter: function (refWord, word) {
66 | if (!word) {
67 | return;
68 | }
69 |
70 | word.parent = this;
71 |
72 | var targetIndex = this.words.indexOf(refWord);
73 | if (targetIndex === -1) {
74 | targetIndex = this.words.length;
75 | } else {
76 | targetIndex += 1;
77 | }
78 |
79 | this.words.splice(targetIndex, 0, word);
80 |
81 | word.split();
82 | },
83 |
84 | insertWordsAfter: function (words) {
85 | var newBlock = new Block(words);
86 | this.parent.insertAfter(this, newBlock);
87 | return newBlock;
88 | },
89 |
90 | /* insertBefore(refWord, word)
91 | *
92 | * Insert a single Word object into this list
93 | * of words, before the provided reference Word (refWord)
94 | *
95 | * If refWord doesn't exist or isn't found, the word
96 | * is added to the front
97 | */
98 | insertBefore: function (refWord, word) {
99 | if (!word) {
100 | return;
101 | }
102 |
103 | word.parent = this;
104 |
105 | var targetIndex = this.words.indexOf(refWord);
106 | if (targetIndex === -1) {
107 | this.words.unshift(word);
108 | } else {
109 | this.words.splice(targetIndex, 0, word);
110 | }
111 |
112 | word.split();
113 | },
114 |
115 | /* removeWordsAfter(refWord)
116 | *
117 | * Remove all the words within this block that
118 | * are after the provided reference Word (refWord)
119 | *
120 | * An array of the removed Word objects is returned
121 | *
122 | * The refWord is NOT removed
123 | */
124 | removeWordsAfter: function (refWord) {
125 | var targetIndex = this.words.indexOf(refWord);
126 | if (targetIndex === -1 || targetIndex === (this.words.length - 1)) {
127 | return [];
128 | }
129 |
130 | var removed = this.words.splice(targetIndex + 1, this.words.length);
131 | removed.forEach(function (word) {
132 | delete word.parent;
133 | });
134 |
135 | return removed;
136 | },
137 |
138 | /* removeWord(word)
139 | *
140 | * Remove the specified Word object
141 | * If this block is empty, it will remove
142 | * itself from the Document
143 | */
144 | removeWord: function (word) {
145 | var index = this.words.indexOf(word);
146 | if (index !== -1) {
147 | this.words.splice(index, 1);
148 | delete word.parent;
149 | }
150 |
151 | // If block is empty, remove it
152 | if (this.words.length === 0) {
153 | this.parent.removeBlock(this);
154 | }
155 |
156 | return word;
157 | },
158 |
159 | splitAndInsertBlocks: function (refWord, wordArrays) {
160 | // Since we're creating new blocks, we will need to move all
161 | // sibling words of this word into the final created block
162 | var siblingWords = this.removeWordsAfter(refWord),
163 | prevBlock = this;
164 |
165 | wordArrays.forEach(function (words) {
166 | prevBlock = prevBlock.insertWordsAfter(words);
167 | });
168 | // If we have sibling words, they need to added to the end
169 | // of the final created block
170 | siblingWords.forEach(function (word) {
171 | prevBlock.insertAfter(null, word);
172 | });
173 | },
174 |
175 | getWords: function () {
176 | return this.words;
177 | },
178 |
179 | getFirstWord: function () {
180 | return this.words[0];
181 | },
182 |
183 | getLastWord: function () {
184 | return this.words[this.words.length - 1];
185 | },
186 |
187 | getChars: function () {
188 | return this.words.reduce(function (prev, curr) {
189 | return prev.concat(curr.getChars());
190 | }, []);
191 | },
192 |
193 | toJSON: function (id) {
194 | var json = {
195 | id: 'b' + id,
196 | name: 'B',
197 | type: this.type,
198 | children: []
199 | };
200 | this.words.forEach(function (word, index) {
201 | json.children.push(word.toJSON(id + '-' + index));
202 | });
203 | return json;
204 | },
205 |
206 | toString: function () {
207 | return this.words.join('');
208 | },
209 |
210 | toHTML: function () {
211 | var content = '';
212 | this.words.forEach(function (word, index) {
213 | content += word.toHTML();
214 | }, this);
215 | return '<' + this.type + '>' + content + '' + this.type + '>';
216 | }
217 | }
218 |
219 | module.exports = Block;
--------------------------------------------------------------------------------
/src/js/char.js:
--------------------------------------------------------------------------------
1 | var Util = require('./util');
2 |
3 | /*
4 | * A Char is an object which represents a single character of text. Currently, this will be where all formatting information will be stored (ie bold, italic, blockquote, etc.).
5 | *
6 | * Char objects will represent every single character within a **Document**. This includes spaces, newlines, and the empty character terminator.
7 | *
8 | * Char objects have 3 main properties:
9 | *
10 | * 1. char
11 | * - The character it contains
12 | * 2. props
13 | * - Key-Value pair representing a formatting property and whether it is applied (ie bold, italic, blockquote)
14 | * 3. parent
15 | * - A reference to its parent Word object.
16 | */
17 | var Char = function (char, parent, props) {
18 | this.parent = parent;
19 |
20 | this.char = char || '';
21 | this.props = props || {};
22 | }
23 |
24 | Char.prototype = {
25 |
26 | getProps: function () {
27 | var props = [];
28 | Object.keys(this.props).forEach(function (prop) {
29 | if (this.props[prop] === true) {
30 | props.push(prop);
31 | }
32 | }, this);
33 | return props;
34 | },
35 |
36 | toJSON: function (id) {
37 | var name = this.char;
38 | if (Util.isNewLine(this.char)) {
39 | name = '\\n';
40 | } else if (Util.isSpace(this.char)) {
41 | name = '[ ]';
42 | }
43 | return {
44 | id: 'c' + id,
45 | name: name,
46 | children: this.getProps()
47 | };
48 | },
49 |
50 | toString: function () {
51 | return this.char;
52 | },
53 |
54 | toHTML: function () {
55 | return this.char;
56 | }
57 | }
58 |
59 | module.exports = Char;
--------------------------------------------------------------------------------
/src/js/document.js:
--------------------------------------------------------------------------------
1 | var Util = require('./util');
2 | var Block = require('./block');
3 | var Word = require('./word');
4 | var Char = require('./char');
5 |
6 | /*
7 | * A Document is the top level object and the root of the tree. It represents all of the text within the editor.
8 | *
9 | * Document objects have 2 main properties:
10 | *
11 | * 1. blocks
12 | * - Array of all the **Block** objects which are its children. These are loosely tied to block elements in that blocks are always separated by new lines.
13 | * 2. chars
14 | * - Array of all the **Char** objects within the entire editor. These are the leaf-nodes of the data tree.
15 | */
16 | var Document = function (text) {
17 | this.chars = [];
18 | this.blocks = [new Block(null, this)];
19 | this.chars = this.blocks.reduce(function (prev, curr) {
20 | return prev.concat(curr.getChars());
21 | }, []);
22 | this.tail = this.chars[0];
23 |
24 | if (text) {
25 | this.insertCharsAt(0, text);
26 | }
27 | }
28 |
29 | Document.prototype = {
30 |
31 | /* execAction(action, selection)
32 | *
33 | * Given an action (ie bold, italic) and a selection data object
34 | * apply the action to all the chars/words within the selection
35 | */
36 | execAction: function (action, selection) {
37 | var nextWord;
38 | // Since this.chars is an array, we can index directly into it to
39 | // find the CHAR nodes within the selection
40 | if (this.chars[selection.start]) {
41 | for (var i = selection.start; i < this.chars.length && i < selection.end; i++) {
42 | var next = this.chars[i];
43 | // For now, let's only apply actions on words. This means just find the parent
44 | // of each char, and apply the action if we haven't already
45 | if (next.parent !== nextWord) {
46 | nextWord = next.parent;
47 | if (nextWord) {
48 | // Call toggleProp(), which should turn the property on/off for the whole word
49 | nextWord.toggleProp(action);
50 | }
51 | }
52 | }
53 | }
54 | },
55 |
56 | /* insertCharsAt(index, str)
57 | *
58 | * Given a string and a target index, create new
59 | * Char objects for each character and insert them into
60 | * the tree data structure.
61 | *
62 | * This includes splitting up the tree when spaces and
63 | * newlines are inserted
64 | */
65 | insertCharsAt: function (index, str) {
66 | if (!str) {
67 | return;
68 | }
69 |
70 | var newChars = [],
71 | nextChar = this.chars[index],
72 | nextWord,
73 | prevChar = this.chars[index - 1],
74 | prevWord;
75 |
76 | str.split('').forEach(function (part) {
77 | newChars.push(new Char(part));
78 | }, this);
79 |
80 | if (Util.exists(nextChar)) {
81 | nextWord = nextChar.parent;
82 | }
83 | if (Util.exists(prevChar)) {
84 | prevWord = prevChar.parent;
85 | }
86 |
87 | if (nextWord === prevWord || !prevWord) {
88 | nextWord.insertBefore(nextChar, newChars);
89 | } else {
90 | if (Util.isNewLine(prevChar.char) || Util.isSpace(prevChar.char)) {
91 | if (nextWord) {
92 | nextWord.insertBefore(null, newChars);
93 | } else {
94 | var newWord = new Word(newChars);
95 | prevWord.parent.insertAfter(prevWord, newWord);
96 | }
97 | } else {
98 | prevWord.insertAfter(prevChar, newChars);
99 | }
100 | }
101 |
102 | // All of the chars now have their proper parent word objects
103 | // and the tree is updated, so just insert the chars into the array
104 | this.chars.splice.apply(this.chars, [index, 0].concat(newChars));
105 | },
106 |
107 | /* removeCharsAt(index, count)
108 | *
109 | * Remove a specified amount of Char objects from the
110 | * tree, starting at the specified index
111 | */
112 | removeCharsAt: function (index, count) {
113 | if (!this.chars[index]) {
114 | return;
115 | }
116 |
117 | var prevChar = this.chars[index - 1];
118 | var lastChar = this.chars[index + count];
119 |
120 | var removedChars = this.chars.splice(index, count);
121 |
122 | removedChars.forEach(function (char) {
123 | char.parent.removeChar(char);
124 | });
125 |
126 | // If both chars are in the same word, we don't need to merge anything
127 | if (prevChar && prevChar.parent !== lastChar.parent) {
128 | prevChar.parent.merge(lastChar.parent);
129 | }
130 | },
131 |
132 | /* insertAfter(refBlock, block)
133 | *
134 | * Insert a single Block object into this list
135 | * of blocks, after the provided reference Block (refBlock)
136 | *
137 | * If refBlock doesn't exist or isn't found, the block
138 | * is added to the end
139 | */
140 | insertAfter: function (refBlock, block) {
141 | if (!block) {
142 | return;
143 | }
144 |
145 | block.parent = this;
146 |
147 | var targetIndex = this.blocks.indexOf(refBlock);
148 | if (targetIndex === -1) {
149 | targetIndex = this.blocks.length;
150 | } else {
151 | targetIndex += 1;
152 | }
153 |
154 | this.blocks.splice(targetIndex, 0, block);
155 | },
156 |
157 | /* removeBlock(block)
158 | *
159 | * Remove the specified block
160 | */
161 | removeBlock: function (block) {
162 | var index = this.blocks.indexOf(block);
163 | if (index !== -1) {
164 | this.blocks.splice(index, 1);
165 | block.parent = null;
166 | }
167 | },
168 |
169 | toJSON: function () {
170 | var json = {
171 | id: 'doc',
172 | name: 'd',
173 | children: []
174 | }
175 | this.blocks.forEach(function (block, index) {
176 | json.children.push(block.toJSON(index));
177 | });
178 | return json;
179 | },
180 |
181 | toString: function () {
182 | return this.blocks.join('');
183 | },
184 |
185 | toHTML: function () {
186 | var str = '';
187 | this.blocks.forEach(function (block) {
188 | str += block.toHTML();
189 | }, this);
190 | return str;
191 | }
192 | }
193 |
194 | module.exports = Document;
--------------------------------------------------------------------------------
/src/js/tree-ux.js:
--------------------------------------------------------------------------------
1 | var jit = require('../../jit/jit');
2 |
3 | var labelType, useGradients, nativeTextSupport, animate;
4 |
5 | (function() {
6 | var ua = navigator.userAgent,
7 | iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
8 | typeOfCanvas = typeof HTMLCanvasElement,
9 | nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
10 | textSupport = nativeCanvasSupport
11 | && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
12 | //I'm setting this based on the fact that ExCanvas provides text support for IE
13 | //and that as of today iPhone/iPad current text support is lame
14 | labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
15 | nativeTextSupport = labelType == 'Native';
16 | useGradients = nativeCanvasSupport;
17 | animate = !(iStuff || !nativeCanvasSupport);
18 | })();
19 |
20 | var Log = {
21 | elem: false,
22 | write: function(text){
23 | if (!this.elem)
24 | this.elem = document.getElementById('log');
25 | this.elem.innerHTML = text;
26 | this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px';
27 | }
28 | };
29 |
30 | var TreeUX = function (elementId) {
31 | var self = this;
32 | this.st = new $jit.ST({
33 | orientation: 'top',
34 | //id of viz container element
35 | injectInto: elementId,
36 | levelsToShow: 4,
37 | //set duration for the animation
38 | duration: 800,
39 | //set animation transition type
40 | transition: $jit.Trans.Quart.easeInOut,
41 | duration: 1,
42 | //set distance between node and its children
43 | levelDistance: 40,
44 | offsetY: 110,
45 | constrained: false,
46 | //enable panning
47 | Navigation: {
48 | enable:true,
49 | panning:true
50 | },
51 | //set node and edge styles
52 | //set overridable=true for styling individual
53 | //nodes or edges
54 | Node: {
55 | height: 20,
56 | width: 15,
57 | type: 'rectangle',
58 | color:'#23A4FF',
59 | align:"center",
60 | overridable: true
61 | },
62 |
63 | Edge: {
64 | type: 'bezier',
65 | overridable: true
66 | },
67 |
68 | onBeforeCompute: function(node){
69 | Log.write("loading " + node.name);
70 | },
71 |
72 | onAfterCompute: function(){
73 | Log.write("done");
74 | },
75 |
76 | //This method is called on DOM label creation.
77 | //Use this method to add event handlers and styles to
78 | //your node.
79 | onCreateLabel: function(label, node){
80 | label.id = node.id;
81 | label.innerHTML = node.name;
82 | label.onclick = function(){
83 | self.st.onClick(node.id);
84 | };
85 | //set label styles
86 | var style = label.style;
87 | style.cursor = 'pointer';
88 | style.color = '#000';
89 | style.fontWeight = 'bold'
90 | style.fontSize = '12px';
91 | style.lineHeight = 20 + 'px';
92 | style.textAlign= 'center';
93 | style.paddingLeft = '2px';
94 | },
95 |
96 | //This method is called right before plotting
97 | //a node. It's useful for changing an individual node
98 | //style properties before plotting it.
99 | //The data properties prefixed with a dollar
100 | //sign will override the global node style properties.
101 | onBeforePlotNode: function(node){
102 | //add some color to the nodes in the path between the
103 | //root node and the selected node.
104 | if (node.selected) {
105 | node.data.$color = "#ff7";
106 | }
107 | else {
108 | delete node.data.$color;
109 | //if the node belongs to the last plotted level
110 | if(!node.anySubnode("exist")) {
111 | //count children number
112 | var count = 0;
113 | node.eachSubnode(function(n) { count++; });
114 | //assign a node color based on
115 | //how many children it has
116 | node.data.$color = ['#aaa', '#baa', '#caa', '#daa', '#eaa', '#faa'][count];
117 | }
118 | }
119 | },
120 |
121 | //This method is called right before plotting
122 | //an edge. It's useful for changing an individual edge
123 | //style properties before plotting it.
124 | //Edge data proprties prefixed with a dollar sign will
125 | //override the Edge global style properties.
126 | onBeforePlotLine: function(adj){
127 | if (adj.nodeFrom.selected && adj.nodeTo.selected) {
128 | adj.data.$color = "#eed";
129 | adj.data.$lineWidth = 3;
130 | }
131 | else {
132 | delete adj.data.$color;
133 | delete adj.data.$lineWidth;
134 | }
135 | }
136 | });
137 | }
138 |
139 | TreeUX.prototype = {
140 | update: function (json) {
141 | json = json || {};
142 | //load json data
143 | this.st.loadJSON(json);
144 | //compute node positions and layout
145 | this.st.compute();
146 | //emulate a click on the root node.
147 | setTimeout(function () {
148 | this.st.onClick(this.st.root);
149 | }.bind(this), 5)
150 | }
151 | }
152 |
153 | module.exports = TreeUX;
--------------------------------------------------------------------------------
/src/js/util.js:
--------------------------------------------------------------------------------
1 | var Util = {
2 |
3 | blockNames: ['address', 'blockquote', 'div', 'dl', 'fieldset', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'noscript', 'ol', 'p', 'pre',
4 |
5 | 'article', 'aside', 'audio', 'canvas', 'dd', 'figcaption', 'figure', 'footer', 'hgroup', 'main', 'nav', 'output', 'section', 'table', 'tfoot', 'ul', 'video',
6 |
7 | 'dt', 'li', 'tbody', 'td', 'th', 'thead', 'tr'],
8 |
9 | CharCode: {
10 | NEW_LINE: 10,
11 | CARRIAGE_RETURN: 13,
12 | SPACE: 32,
13 | NBSP: 160
14 | },
15 |
16 | Char: {},
17 |
18 | exists: function (v) {
19 | return v || v === '' || v === 0 || v === false;
20 | },
21 |
22 | isNewLine: function (str) {
23 | return !!(str && str.charCodeAt(0) === this.CharCode.NEW_LINE);
24 | },
25 |
26 | isSpace: function (str) {
27 | return !!(str && str.match(/^\s+$/) && !this.isNewLine(str));
28 | },
29 |
30 | createHTMLWordString: function (root) {
31 | var skipRoot = false;
32 | if (this.blockNames.indexOf(root.nodeName.toLowerCase()) !== -1) {
33 | skipRoot = true;
34 | }
35 | var x = null,
36 | treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, x, false);
37 | str = '',
38 | hitNonBlock = false;
39 | while (treeWalker.nextNode()) {
40 | var node = treeWalker.currentNode;
41 | if (skipRoot && node === root) {
42 | continue;
43 | }
44 | if (node.nodeType === 3) {
45 | str += node.nodeValue;
46 | hitNonBlock = true;
47 | } else {
48 | if (this.blockNames.indexOf(node.nodeName.toLowerCase()) !== -1) {
49 | if (hitNonBlock) {
50 | str += this.Char.NEW_LINE;
51 | }
52 | } else {
53 | hitNonBlock = true;
54 | }
55 | }
56 | }
57 | return str.replace(new RegExp(this.Char.NBSP, 'g'), this.Char.SPACE);
58 | },
59 |
60 | exportSelection: function (root) {
61 | if (!root) {
62 | return null;
63 | }
64 |
65 | var selectionState = null,
66 | selection = document.getSelection();
67 |
68 | if (selection.rangeCount > 0) {
69 | var range = selection.getRangeAt(0),
70 | preSelectionRange = range.cloneRange(),
71 | start;
72 |
73 | preSelectionRange.selectNodeContents(root);
74 | preSelectionRange.setEnd(range.startContainer, range.startOffset);
75 | start = preSelectionRange.toString().length;
76 |
77 | selectionState = {
78 | start: start,
79 | end: start + range.toString().length
80 | };
81 | }
82 |
83 | return selectionState;
84 | },
85 |
86 | importSelection: function (selectionState, root) {
87 | if (!selectionState || !root) {
88 | return;
89 | }
90 |
91 | var range = document.createRange();
92 | range.setStart(root, 0);
93 | range.collapse(true);
94 |
95 | var node = root,
96 | nodeStack = [],
97 | charIndex = 0,
98 | foundStart = false,
99 | stop = false,
100 | nextCharIndex;
101 |
102 | while (!stop && node) {
103 | if (node.nodeType === 3) {
104 | nextCharIndex = charIndex + node.length;
105 | if (!foundStart && selectionState.start >= charIndex && selectionState.start <= nextCharIndex) {
106 | range.setStart(node, selectionState.start - charIndex);
107 | foundStart = true;
108 | }
109 | if (foundStart && selectionState.end >= charIndex && selectionState.end <= nextCharIndex) {
110 | range.setEnd(node, selectionState.end - charIndex);
111 | stop = true;
112 | }
113 | charIndex = nextCharIndex;
114 | } else {
115 | var i = node.childNodes.length - 1;
116 | while (i >= 0) {
117 | nodeStack.push(node.childNodes[i]);
118 | i -= 1;
119 | }
120 | }
121 | if (!stop) {
122 | node = nodeStack.pop();
123 | }
124 | }
125 |
126 | var sel = document.getSelection();
127 | sel.removeAllRanges();
128 | sel.addRange(range);
129 | }
130 | }
131 |
132 | Object.keys(Util.CharCode).forEach(function (name) {
133 | Util.Char[name] = String.fromCharCode(Util.CharCode[name]);
134 | });
135 |
136 | module.exports = Util;
--------------------------------------------------------------------------------
/src/js/word.js:
--------------------------------------------------------------------------------
1 | var Util = require('./util');
2 | var Char = require('./char');
3 |
4 | /*
5 | * A Word is an object which represents a chunk of text which is separated by other chunks of text by spaces (within the same **Block**). All words will contain their ending character, which will either be:
6 | * - A Space (' ')
7 | * - A Newline ('\n')
8 | * - An Empty String ('')
9 | * - The last word in the **Document** will have this empty string as a terminator
10 | *
11 | * Word objects have 2 main properties:
12 | *
13 | * 1. chars
14 | * - Array of all the Char objects which are its children.
15 | * 2. parent
16 | * - A reference to its parent Block object.
17 | */
18 | var Word = function (text, parent) {
19 | this.parent = parent;
20 |
21 | if (!text && text !== '') {
22 | this.chars = [];
23 | } else if (typeof text === 'string') {
24 | this.chars = [];
25 | var chars = (text) ? Array.prototype.slice.call(text) : [''];
26 | chars.forEach(function (char) {
27 | this.chars.push(new Char(char, this));
28 | }, this);
29 | } else {
30 | this.chars = text;
31 | this.chars.forEach(function (char) {
32 | char.parent = this;
33 | }, this);
34 | }
35 | }
36 |
37 | Word.prototype = {
38 |
39 | /* toggleProp(prop)
40 | *
41 | * Given some property name (ie bold, italic), toggle its value for
42 | * all of the chars within this word
43 | *
44 | */
45 | toggleProp: function (prop) {
46 | var setTrue = false;
47 | /* Loop through each char
48 | * If a char has a false value for the property, set it to true
49 | *
50 | * ie: If half a word is bold, make the whole word bold
51 | */
52 | this.chars.forEach(function (char) {
53 | if (!char.props[prop]) {
54 | char.props[prop] = true;
55 | setTrue = true;
56 | }
57 | });
58 |
59 | /* If the entire word already had the property set to true
60 | * loop back through and turn the property off.
61 | *
62 | * ie: If an entire word is already bold, make it all unbold
63 | */
64 | if (!setTrue) {
65 | this.chars.forEach(function (char) {
66 | char.props[prop] = false;
67 | });
68 | }
69 | },
70 |
71 | /* merge(word)
72 | *
73 | * merge the provided word into this word
74 | */
75 | merge: function (word) {
76 | // If the words are in separate blocks, we need to merge the blocks
77 | if (this.parent !== word.parent) {
78 | // Calling block.merge() will handle merging the words too
79 | this.parent.merge(word.parent);
80 | return;
81 | }
82 |
83 | // Remove each char from the other word, and add it to this one
84 | while (word.getChars().length) {
85 | var nextChar = word.removeChar(word.getFirstChar());
86 | nextChar.parent = this;
87 | this.chars.push(nextChar);
88 | }
89 |
90 | // We might have ended with a space, or the other word may have started
91 | // with a space, so do a split to make sure
92 | this.split();
93 | },
94 |
95 | /* split()
96 | *
97 | * Look for spaces and newlines within this word
98 | * Each space means create a new words
99 | * Each newline means create a new block
100 | */
101 | split: function () {
102 | var currentChars = [],
103 | thisBlockWords = [],
104 | thisWordChars,
105 | newBlocks = [],
106 | nextBlock;
107 |
108 | this.chars.forEach(function (char, index, array) {
109 | currentChars.push(char);
110 | if (index === array.length - 1) {
111 | return;
112 | }
113 | // We hit something which will end a word and could end a block
114 | if (Util.isNewLine(char.char) || Util.isSpace(char.char)) {
115 | // If we aren't adding to a newWord, that means we're still in the original
116 | if (!thisWordChars) {
117 | thisWordChars = currentChars;
118 | } else {
119 | // Add the newChars to a new word
120 | if (!nextBlock) {
121 | thisBlockWords.push(new Word(currentChars));
122 | } else {
123 | nextBlock.push(new Word(currentChars));
124 | }
125 | }
126 | currentChars = [];
127 |
128 | // If we hit a newline, we need to start a new block
129 | if (Util.isNewLine(char.char)) {
130 | if (nextBlock) {
131 | newBlocks.push(nextBlock);
132 | }
133 | nextBlock = [];
134 | }
135 | }
136 | }, this);
137 |
138 | // If we never hit a space, do nothing
139 | if (!thisWordChars) {
140 | return;
141 | }
142 |
143 | // Update our list of chars
144 | this.chars = thisWordChars;
145 |
146 | // If we have any lingering chars, make sure they get added into a word or block
147 | if (currentChars.length) {
148 | if (!nextBlock) {
149 | thisBlockWords.push(new Word(currentChars));
150 | } else {
151 | nextBlock.push(new Word(currentChars));
152 | }
153 | }
154 |
155 | // If we have any lingering blocks, make sure they get added into the blocks list
156 | if (nextBlock) {
157 | newBlocks.push(nextBlock);
158 | }
159 |
160 | // First, let's add any new words to this block
161 | var lastWord = this;
162 | if (thisBlockWords.length) {
163 | thisBlockWords.forEach(function (word) {
164 | lastWord.parent.insertAfter(lastWord, word);
165 | lastWord = word;
166 | });
167 | }
168 |
169 | // Now, let's start creating blocks
170 | if (newBlocks.length) {
171 | this.parent.splitAndInsertBlocks(lastWord, newBlocks);
172 | }
173 | },
174 |
175 | /* insertAfter(refChar, char)
176 | *
177 | * Insert an array of Char objects into this word
178 | * all after the provided reference char (refChar)
179 | *
180 | * If refChar doesn't exist or isn't found, all the chars
181 | * are added to the end
182 | */
183 | insertAfter: function (refChar, chars) {
184 | if (!chars) {
185 | return;
186 | }
187 |
188 | chars.forEach(function (char) {
189 | char.parent = this;
190 | }, this);
191 |
192 | var targetIndex = this.chars.indexOf(refChar);
193 | if (targetIndex === -1) {
194 | this.chars = this.chars.concat(chars);
195 | } else {
196 | targetIndex = targetIndex + 1;
197 | this.chars.splice.apply(this.chars, [targetIndex, 0].concat(chars));
198 | }
199 |
200 | this.split();
201 | },
202 |
203 | /* insertBefore(refChar, char)
204 | *
205 | * Insert an array of Char objects into this word
206 | * all before the provided reference char (refChar)
207 | *
208 | * If refChar doesn't exist or isn't found, all the chars
209 | * are inserted at the beginning of the word
210 | */
211 | insertBefore: function (refChar, chars) {
212 | if (!chars) {
213 | return;
214 | }
215 |
216 | chars.forEach(function (char) {
217 | char.parent = this;
218 | }, this);
219 |
220 | var targetIndex = this.chars.indexOf(refChar);
221 | if (targetIndex === -1) {
222 | this.chars = chars.concat(this.chars);
223 | } else {
224 | this.chars.splice.apply(this.chars, [targetIndex, 0].concat(chars));
225 | }
226 |
227 | this.split();
228 | },
229 |
230 | /* removeChar(char)
231 | *
232 | * Remove the provided Char object from the list
233 | * of chars in this word.
234 | * If the word becomes empty, it will remove
235 | * itself from the block it's in
236 | */
237 | removeChar: function (char) {
238 | var index = this.chars.indexOf(char);
239 | if (index !== -1) {
240 | this.chars.splice(index, 1);
241 | delete char.parent;
242 | }
243 |
244 | // If word is empty, remove it
245 | if (this.chars.length === 0) {
246 | this.parent.removeWord(this);
247 | }
248 |
249 | return char;
250 | },
251 |
252 | getChars: function () {
253 | return this.chars;
254 | },
255 |
256 | getFirstChar: function () {
257 | return this.chars[0];
258 | },
259 |
260 | getLastChar: function () {
261 | return this.chars[this.chars.length - 1];
262 | },
263 |
264 | toJSON: function (id) {
265 | var json = {
266 | id: 'w' + id,
267 | name: 'w',
268 | children: []
269 | };
270 | this.chars.forEach(function (char, index) {
271 | json.children.push(char.toJSON(id + '-' + index));
272 | });
273 | return json;
274 | },
275 |
276 | toString: function () {
277 | return this.chars.join('');
278 | },
279 |
280 | toHTML: function () {
281 | var tags = {},
282 | pre = '',
283 | post = '',
284 | content = '';
285 | this.chars.forEach(function (next) {
286 | if (!Util.isNewLine(next.char)) {
287 | next.getProps().forEach(function (prop) {
288 | tags[prop] = true;
289 | });
290 | content += next.toHTML();
291 | }
292 | }, this);
293 | Object.keys(tags).forEach(function (tag) {
294 | pre = pre + '<' + tag + '>';
295 | post = '' + tag + '>' + post;
296 | });
297 | return pre + content + post;
298 | }
299 | }
300 |
301 | module.exports = Word;
--------------------------------------------------------------------------------
/src/js/words.js:
--------------------------------------------------------------------------------
1 | var Util = require('./util');
2 | var Document = require('./document');
3 | var JsDiff = require('diff');
4 | var TreeUX;
5 |
6 | if (typeof window !== 'undefined') {
7 | TreeUX = require('./tree-ux');
8 | }
9 |
10 | var Words = function (selector) {
11 | this.element = document.querySelector(selector);
12 | this.element.setAttribute('contenteditable', true);
13 |
14 | this.element.addEventListener('input', this.onInput.bind(this));
15 |
16 | this.doc = new Document(Util.createHTMLWordString(this.element));
17 |
18 | // Attach to click for the toolbar
19 | Array.prototype.slice.call(document.querySelectorAll('button')).forEach(function (button) {
20 | button.addEventListener('click', this.onToolbarButtonClick.bind(this));
21 | }, this);
22 |
23 | if (TreeUX) {
24 | // Just for help while developing, create a visualization
25 | // that shows the JSON tree-structure while text is being edited
26 | this.treeUx = new TreeUX('tree-ux');
27 | }
28 |
29 | // Build tree from initial content
30 | this.updateState(this.element);
31 | }
32 |
33 | Words.prototype = {
34 |
35 | onToolbarButtonClick: function (event) {
36 | var target = event.currentTarget;
37 | if (target.hasAttribute('data-custom-action')) {
38 | this.execCustomAction(target.getAttribute('data-custom-action'));
39 | }
40 | },
41 |
42 | execCustomAction: function (action) {
43 | // Export selection, getting start character and end character
44 | var selection = Util.exportSelection(this.element);
45 |
46 | // Execute action, providing given selection
47 | this.doc.execAction(action, selection);
48 |
49 | // Replace the current content with the generated HTML
50 | this.element.innerHTML = this.doc.toHTML();
51 |
52 | // Restore the selection before the action occurred
53 | Util.importSelection(selection, this.element);
54 | },
55 |
56 | updateState: function (element) {
57 | var nextStr = Util.createHTMLWordString(element), // text representation of current DOM
58 | currStr = this.doc.toString(), // text representation of the current tree
59 | diff = JsDiff.diffChars(currStr, nextStr), // JsDiff of two strings
60 | index = 0;
61 |
62 | /* Iterate through array of diffs detected by JSDiff
63 | *
64 | * Each 'diff' is an object that represents a part of the string:
65 | *
66 | * {
67 | * added: true/undefined (True if this represents a chunk of text that was added)
68 | * removed: true/undefined (True if this represents a chunk of text that was removed)
69 | * value: string (The chunk of text this diff covers)
70 | * count: int (The length of this chunk of text)
71 | * }
72 | *
73 | * NOTE: If added and removed are both undefined this chunk of text text was unchanged
74 | */
75 | diff.forEach(function (action) {
76 | if (action.removed) {
77 | this.doc.removeCharsAt(index, action.count);
78 | } else {
79 | if (action.added) {
80 | this.doc.insertCharsAt(index, action.value);
81 | }
82 | index += action.value.length;
83 | }
84 | }, this);
85 |
86 | // For development only, update the tree visualization
87 | var js = this.doc.toJSON();
88 | if (this.treeUx) {
89 | this.treeUx.update(js);
90 | }
91 | },
92 |
93 | onInput: function (event) {
94 | this.updateState(event.currentTarget);
95 | }
96 | }
97 |
98 | Words.Util = Util;
99 | Words.Char = require('./char');
100 | Words.Word = require('./word');
101 | Words.Block = require('./block');
102 | Words.Document = Document;
103 |
104 | global.Words = module.exports = Words;
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | *:focus {
2 | outline: none;
3 | }
4 |
5 | body {
6 | font-family: Helvetica, Arial, sans-serif;
7 | font-size: 22px;
8 | line-height: 30px;
9 | }
10 |
11 | .top-bar {
12 | position: fixed;
13 | top: 0;
14 | left: 0;
15 | width: auto;
16 | z-index: 10;
17 | padding: 10px;
18 | background-color: #000;
19 | background-color: rgba(0, 0, 0, .8);
20 | box-shadow: 0 0 4px #000;
21 | box-sizing: border-box;
22 | color: #ccc;
23 | font-size: 12px;
24 | font-weight: bold;
25 | text-align: center;
26 | text-transform: uppercase;
27 | }
28 |
29 | h1 {
30 | font-size: 60px;
31 | font-weight: bold;
32 | text-align: center;
33 | margin-bottom: 40px;
34 | padding-bottom: 40px;
35 | letter-spacing: -2px;
36 | border-bottom: 1px solid #dbdbdb;
37 | }
38 |
39 | h2 {
40 | font-size: 32px;
41 | line-height: 42px;
42 | }
43 |
44 | h3 {
45 | font-size: 26px;
46 | line-height: 32px;
47 | }
48 |
49 | h4 {
50 | font-size: 24px;
51 | line-height: 28px;
52 | }
53 |
54 | p {
55 | margin-bottom: 40px;
56 | }
57 |
58 | a {
59 | color:black;
60 | }
61 |
62 | a:hover {
63 | color:green;
64 | }
65 |
66 | pre {
67 | font-family: 'Menlo', monospace;
68 | font-size: 15px;
69 | background-color: #f0f0f0;
70 | padding: 15px;
71 | border: 1px solid #ccc;
72 | border-radius: 5px;
73 | color: #666;
74 | }
75 |
76 |
77 | blockquote {
78 | display: block;
79 | padding-left: 20px;
80 | border-left: 6px solid #df0d32;
81 | margin-left: -15px;
82 | padding-left: 15px;
83 | font-style: italic;
84 | color: #555;
85 | }
86 |
87 | #container {
88 | width: 960px;
89 | margin: 30px auto;
90 | }
91 |
92 | .editable,
93 | .secondEditable
94 | {
95 | outline: none;
96 | margin: 0 0 20px 0;
97 | padding: 0 0 20px 0;
98 | border-bottom: 1px solid #dbdbdb;
99 | }
100 |
101 | #columns {
102 | width: 90%;
103 | margin: 30px auto;
104 | }
105 |
106 | .column-container {
107 |
108 | }
109 |
110 | .column {
111 | vertical-align: top;
112 | display: inline-block;
113 | width: 30%;
114 | margin: 10px 1%;
115 | }
116 |
117 |
118 |
119 |
120 |
121 | #log {
122 | position:relative;
123 | top:10px;
124 | font-size:1.0em;
125 | font-weight:bold;
126 | color:#23A4FF;
127 | }
128 |
129 |
130 | #tree-ux {
131 | position:relative;
132 | width:100%;
133 | height:400px;
134 | margin:auto;
135 | overflow:hidden;
136 | }
--------------------------------------------------------------------------------
/test/unit/char.spec.js:
--------------------------------------------------------------------------------
1 | var expect = require('chai').expect;
2 |
3 | var Char = require('../../src/js/char');
4 |
5 | describe('Char', function () {
6 | describe('constructor', function () {
7 | it('should exist', function () {
8 | expect(Char).not.to.be.undefined;
9 | });
10 |
11 | it('should initialize core properties', function () {
12 | var char = new Char();
13 |
14 | expect(char.parent).to.be.undefined;
15 | expect(char.char).to.be.a('string');
16 | expect(char.char).to.be.empty;
17 | expect(char.props).to.be.a('object');
18 | expect(char.props).to.be.empty;
19 | });
20 |
21 | it('should accept a character and a parent reference', function () {
22 | var tempParent = {},
23 | tempChar = 'X',
24 | char = new Char('X', tempParent);
25 |
26 | expect(char.char).to.equal(tempChar);
27 | expect(char.parent).to.equal(tempParent);
28 | });
29 |
30 | it('should accept props as an object', function () {
31 | var props = {
32 | 'b': true,
33 | 'i': false
34 | },
35 | char = new Char('X', null, props);
36 |
37 | expect(char.props).to.equal(props);
38 | expect(char.getProps()).to.deep.equal(['b']);
39 | });
40 | });
41 |
42 | describe('getProps', function () {
43 | it('should return properties as an array', function () {
44 | var char = new Char('a');
45 |
46 | char.props['PROP'] = true;
47 | char.props['B'] = true;
48 |
49 | var props = char.getProps();
50 | expect(props).to.be.an.instanceof(Array);
51 | expect(props.length).to.equal(2);
52 | expect(props[0]).to.equal('PROP');
53 | expect(props[1]).to.equal('B');
54 | });
55 |
56 | it('should return properties that have a value of true', function () {
57 | var char = new Char('a');
58 |
59 | char.props['B'] = 'B';
60 | char.props['I'] = true;
61 | char.props['U'] = null;
62 | char.props['P'] = false;
63 |
64 | var props = char.getProps();
65 | expect(props.length).to.equal(1);
66 | expect(props[0]).to.equal('I');
67 | });
68 |
69 | it('should return an empty array when nothing is true', function () {
70 | var char = new Char('a');
71 |
72 | expect(char.getProps()).to.be.empty;
73 |
74 | char['B'] = 'B';
75 | expect(char.getProps()).to.be.empty;
76 | });
77 | });
78 |
79 | describe('toJSON', function () {
80 | it('should return a JSON representaton of the char', function () {
81 | var char = new Char('a'),
82 | json = char.toJSON(1),
83 | output = {
84 | name: 'a',
85 | id: 'c1',
86 | children: []
87 | };
88 |
89 | expect(json).to.deep.equal(output);
90 | });
91 |
92 | it('should return JSON containing props as children', function () {
93 | var char = new Char('b');
94 |
95 | char.props['B'] = true;
96 | char.props['I'] = false;
97 |
98 | var output = {
99 | name: 'b',
100 | id: 'c2',
101 | children: ['B']
102 | };
103 |
104 | expect(char.toJSON(2)).to.deep.equal(output);
105 | });
106 |
107 | it('should return [ ] for spaces', function () {
108 | var char = new Char(' ');
109 |
110 | expect(char.toJSON('c')).to.deep.equal({
111 | name: '[ ]',
112 | id: 'cc',
113 | children: []
114 | });
115 | });
116 |
117 | it('should return \\n for new lines', function () {
118 | var char = new Char('\n');
119 |
120 | expect(char.toJSON('x')).to.deep.equal({
121 | name: '\\n',
122 | id: 'cx',
123 | children: []
124 | });
125 | });
126 | });
127 |
128 | describe('toString and toHTML', function () {
129 | it('should return the character', function () {
130 | var char = new Char('a'),
131 | str = char.toString(),
132 | html = char.toHTML();
133 |
134 | expect(str).to.be.a('string');
135 | expect(str).to.equal('a');
136 | expect(html).to.be.a('string');
137 | expect(html).to.equal('a');
138 | });
139 |
140 | it('should return empty string by default', function () {
141 | var char = new Char(),
142 | str = char.toString(),
143 | html = char.toHTML();
144 |
145 | expect(str).to.be.a('string');
146 | expect(str).to.be.empty;
147 | expect(html).to.be.a('string');
148 | expect(html).to.be.empty;
149 | });
150 | });
151 | });
--------------------------------------------------------------------------------
/test/unit/util.spec.js:
--------------------------------------------------------------------------------
1 | var expect = require('chai').expect;
2 |
3 | var Util = require('../../src/js/util');
4 |
5 | describe('Util', function () {
6 | describe('exists', function () {
7 | it('should return true for empty string false and 0', function () {
8 | expect(Util.exists('')).to.be.true;
9 | expect(Util.exists(false)).to.be.true;
10 | expect(Util.exists(0)).to.be.true;
11 | });
12 |
13 | it('should return false for null and undefined', function () {
14 | expect(Util.exists(undefined)).to.be.false;
15 | expect(Util.exists(null)).to.be.false;
16 | });
17 |
18 | it('should return false for a deleted property', function () {
19 | var obj = { prop: false };
20 | expect(Util.exists(obj.prop)).to.be.true;
21 |
22 | delete obj.prop;
23 | expect(Util.exists(obj.prop)).to.be.false;
24 | });
25 | });
26 |
27 | describe('isNewLine', function () {
28 | it('should return true for \\n', function () {
29 | expect(Util.isNewLine('\n')).to.be.true;
30 | expect(Util.isNewLine('\r')).to.be.false;
31 | expect(Util.isNewLine(' ')).to.be.false;
32 | });
33 | });
34 |
35 | describe('isSpace', function () {
36 | it('should return true for spaces', function () {
37 | var whiteSpaces = [' ', '\t', '\v', '\f', '\u00A0', '\u2000', '\u2001', '\u2002', '\u2003','\u2028', '\u2029'];
38 |
39 | whiteSpaces.forEach(function (str) {
40 | expect(Util.isSpace(str)).to.be.true;
41 | });
42 | });
43 |
44 | it('should return false for new line chars and empty strings', function () {
45 | expect(Util.isSpace('\n')).to.be.false;
46 | expect(Util.isSpace('')).to.be.false;
47 | });
48 | });
49 | });
--------------------------------------------------------------------------------