21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "maxErrors": 1000000,
3 | "disallowMixedSpacesAndTabs": true,
4 | "disallowMultipleLineBreaks": true,
5 | "disallowQuotedKeysInObjects": true,
6 | "disallowTabs": true,
7 | "disallowSpaceBeforeComma": true,
8 | "disallowSpaceBeforeSemicolon": true,
9 | "disallowUnusedParams": true,
10 | "disallowSpaceAfterObjectKeys": true,
11 | "disallowSpaceAfterPrefixUnaryOperators": true,
12 | "disallowSpaceBeforePostfixUnaryOperators": true,
13 | "disallowSpaceBeforeBinaryOperators": [
14 | ","
15 | ],
16 | "disallowTrailingWhitespace": true,
17 | "disallowTrailingComma": true,
18 | "disallowYodaConditions": true,
19 | "disallowKeywordsOnNewLine": [
20 | "else"
21 | ],
22 | "disallowKeywords": [
23 | "with"
24 | ],
25 | "requireSpaceBeforeBlockStatements": true,
26 | "requireParenthesesAroundIIFE": true,
27 | "requireSpacesInConditionalExpression": true,
28 | "requireBlocksOnNewline": 1,
29 | "requireCommaBeforeLineBreak": true,
30 | "requireSpaceBeforeBinaryOperators": true,
31 | "requireSpaceAfterBinaryOperators": true,
32 | "requireCamelCaseOrUpperCaseIdentifiers": true,
33 | "requireLineFeedAtFileEnd": true,
34 | "requireCapitalizedConstructors": true,
35 | "requireDotNotation": true,
36 | "requirePaddingNewLinesAfterUseStrict": true,
37 | "requireSpaceAfterComma": true,
38 | "requireSpaceAfterLineComment": true,
39 | "requireSpacesInFunctionDeclaration": {
40 | "beforeOpeningRoundBrace": true
41 | },
42 | "requireCurlyBraces": [
43 | "do",
44 | "catch",
45 | "else",
46 | "finally",
47 | "for",
48 | "if",
49 | "try",
50 | "while"
51 | ],
52 | "requireSpaceAfterKeywords": [
53 | "if",
54 | "else",
55 | "for",
56 | "while",
57 | "do",
58 | "switch",
59 | "case",
60 | "return",
61 | "try",
62 | "catch",
63 | "typeof"
64 | ],
65 | /*"safeContextKeyword": "_this",*/
66 | "requireSemicolons": true,
67 | "validateLineBreaks": "LF",
68 | "validateQuoteMarks": "'",
69 | "requireAnonymousFunctions": true,
70 | "validateIndentation": 4,
71 | "jsDoc": {
72 | "checkAnnotations": true,
73 | "checkParamExistence": true,
74 | "checkParamNames": true,
75 | "checkRedundantReturns": true,
76 | "checkReturnTypes": true,
77 | "checkTypes": true,
78 | "enforceExistence": true,
79 | "requireDescriptionCompleteSentence": true,
80 | "requireNewlineAfterDescription": true,
81 | "requireParamDescription": true,
82 | "requireReturnDescription": true,
83 | "requireReturnTypes": true
84 | },
85 | "requireCapitalizedConstructorsNew": true
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "maxerr": 50,
3 | "esversion": 6,
4 | "bitwise": true,
5 | "camelcase": true,
6 | "curly": true,
7 | "eqeqeq": false,
8 | "forin": true,
9 | "freeze": true,
10 | "immed": true,
11 | "latedef": false,
12 | "newcap": true,
13 | "noarg": true,
14 | "noempty": true,
15 | "nonbsp": true,
16 | "nonew": true,
17 | "plusplus": false,
18 | "quotmark": "single",
19 | "undef": true,
20 | "unused": true,
21 | "strict": true,
22 | "indent": 2,
23 | "asi": false,
24 | "boss": false,
25 | "debug": false,
26 | "eqnull": true,
27 | "moz": false,
28 | "evil": false,
29 | "expr": true,
30 | "funcscope": false,
31 | "globalstrict": false,
32 | "iterator": false,
33 | "lastsemic": false,
34 | "laxbreak": true,
35 | "laxcomma": false,
36 | "loopfunc": true,
37 | "multistr": false,
38 | "noyield": false,
39 | "notypeof": false,
40 | "proto": false,
41 | "scripturl": false,
42 | "shadow": false,
43 | "sub": true,
44 | "supernew": false,
45 | "validthis": false,
46 | "browser": true,
47 | "browserify": false,
48 | "couch": false,
49 | "devel": false,
50 | "dojo": false,
51 | "jasmine": false,
52 | "jquery": false,
53 | "mocha": true,
54 | "mootools": false,
55 | "node": false,
56 | "nonstandard": false,
57 | "phantom": false,
58 | "prototypejs": false,
59 | "qunit": false,
60 | "rhino": false,
61 | "shelljs": false,
62 | "typed": false,
63 | "worker": false,
64 | "wsh": false,
65 | "yui": false,
66 | "maxlen": 120,
67 | "predef": [
68 | "d3",
69 | "d3.tip"
70 | ]
71 | }
72 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "5"
4 | - "6"
5 | before_install: npm install -g grunt-cli
6 | install: npm install
7 |
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 1.2.2 (5/16/2016)
2 | * Removed the Object/Array prototypes to prevent them from conflicting with other frameworks.
3 | * Fixed a spacing issue that was caused by having the wrong font size.
4 | * Added a check to prevent the SVG from being created multiple times.
5 | * Minor optimizations, fixed a resizing bug, moved the default color array into the constructor to prevent it from being created every time 'data' was called, finished adding in the thresholds, and added transitions.
6 | * Determine the direction of the tooltip based on the location and updated the CSS.
7 | * Added bower.json and a README.
8 |
9 | # 1.3.0 (5/17/2016 - 5/19/2016)
10 | * Pulled d3-tip into the source code to make modifications to add a way to determine the direction of the tip so that the tip doesn't go off the screen.
11 | * Minified the CSS stylesheet.
12 | * Added a way to configure the truncate cap in the configuration object.
13 | * Removed d3-tip from the dependencies.
14 | * Added AMD and CommonJS support.
15 | * Fixed a bug that was causing the resize of the SVG to calculate the width and height incorrectly.
16 | * Made *data* return the RelationshipGraph object to keep d3's chaining functionality working.
17 | * Fixed a bug where if the value was a number, the threshold wouldn't work.
18 | * Used JSCS to enforce styling.
19 | * Added grunt tasks.
20 | * Added a TravisCI yaml file for tests.
21 | * Added CSSLint
22 | * Began adding in unit tests.
23 | * Updated algorithm for determining if the tooltip should be relocated.
24 | * Added sorting to the thresholds if it is made up of numbers.
25 |
26 | # 1.4.1 (5/19/2016 - 5/21/2016)
27 | * Added additional tests and fixed the bugs that came with that.
28 | * Updated d3 to 3.5.17
29 | * Fixed a bug that made the sorting different each time.
30 | * Finished the test suite.
31 |
32 | # 1.4.2 (5/21/2016 - 5/26/2016)
33 | * Updated dev dependencies.
34 | * Reduced the complexity of the *data* method by splitting it up into separate private methods.
35 | * Moved the all private methods into one area.
36 | * Added the ability to not pass in thresholds and all the blocks be the same color.
37 | * Right aligned the parent labels.
38 |
39 | # 1.5.0 (5/26/2016 - 6/12/2016)
40 | * Created a non-minified js file in dest using grunt-contrib-concat.
41 | * Added a test to check the colors of the blocks to make sure they're correct.
42 | * Made the comparison between the value and the threshold case insensitive, added type checking for the threshold comparisons, and made sure that the key appears in title case when the tooltip comes up.
43 | * Fixed a bug where clicking `Random` twice (or more) on example page causes the demo to keep cycling.
44 | * Moved the child nodes five pixels away from the parent labels to make the space larger.
45 | * Optimized the code by using local variables instead of accessing object properties multiple times and made static functions instead of recreating them in loops.
46 | * Fixed a bug where the number thresholds had to be exact instead of between two thresholds.
47 | * Fixed a bug where only the first word in the tooltip key was capitalized instead of the key being in title case.
48 | * Fixed the regex for numeric comparisons so that it would take negative numbers into account.
49 | * Added additional tests.
50 | * Fixed the way that the width of the parent labels was determined and added a cache.
51 | * Optimized parent labels by storing the keys instead of generating it each time.
52 | * Added a way to add a custom sort function.
53 | * Added a way to set a custom string for the `value` key instead of having it always say 'value' on the tooltip.`
54 | * Added support for private data by using the `_private_` key in the JSON data.
55 |
56 | # 2.0.0 (6/12/2016-7/08/2016)
57 | * Added a way to set the onclick function for a parent label.
58 | * Cleaned up some of the code.
59 | * Fixed an SVG width issue where if no data was supplied, the width and height were set to -15, which threw an exception.
60 | * Fixed a bug where if the tooltip width and height got too big, the arrow wasn't pointing at the child node.
61 | * Fixed a bug where the width of the SVG was being determined incorrectly.
62 | * Added a way to not show the value on the tooltip by setting the `valueKeyName` to an empty string.
63 | * Added a cursor pointer if there is an onClick function.
64 | * Rewrote the source in ES6 and d3 v4.1.0
65 | * Added in some missing ES6 conversions.
66 |
67 | # 2.1.0 (7/08/2016-10/02/2016)
68 | * Added interaction methods with the child nodes to allow users to change the color of the node and the stroke color.
69 | * Added a way to query objects based on sub objects.
70 | * Lazily loaded the node interaction methods.
71 | * Made graph backwards compatible with d3 v3.
72 | * Changed the CSS to SCSS.
73 | * Fixed the spacing between the child nodes.
74 | * Updated uglify to version 2.0.0
75 | * Fixed a bug where the IDs given to the child nodes were the same. This caused the node in row 1, index 22, to have the same ID as the node in row 12, index 2 (for example).
76 |
77 | # 2.1.2 (10/02/2016-)
78 | * Fixed a bug where the colors were not being set correctly for the children nodes because the color was being returned as `000000` instead of `#000000`.
79 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /* global module, grunt, initConfig */
2 | module.exports = function(grunt) {
3 | 'use strict';
4 |
5 | grunt.initConfig({
6 | concat: {
7 | options: {
8 | separator: ' '
9 | },
10 | dist: {
11 | src: ['src/d3-tip.js', 'src/index.js'],
12 | dest: 'dest/d3.relationshipgraph.js'
13 | }
14 | },
15 | babel: {
16 | options: {
17 | presets: ['es2015']
18 | },
19 | dist: {
20 | files: {
21 | 'dest/d3.relationshipgraph.js': 'dest/d3.relationshipgraph.js'
22 | }
23 | }
24 | },
25 | uglify: {
26 | options: {
27 | mangle: false
28 | },
29 | target: {
30 | files: {
31 | 'dest/d3.relationshipgraph.min.js': 'dest/d3.relationshipgraph.js'
32 | }
33 | }
34 | },
35 | cssmin: {
36 | target: {
37 | files: {
38 | 'dest/d3.relationshipgraph.min.css': 'src/RelationshipGraph.css'
39 | }
40 | }
41 | },
42 | jshint: {
43 | all: {
44 | 'src': 'src/index.js',
45 | options: {
46 | jshintrc: '.jshintrc'
47 | }
48 | }
49 | },
50 | jscs: {
51 | src: 'src/index.js',
52 | options: {
53 | config: '.jscsrc'
54 | }
55 | },
56 | csslint: {
57 | options: {
58 | csslintrc: '.csslintrc'
59 | },
60 | src: ['src/RelationshipGraph.css']
61 | },
62 | mocha: {
63 | test: {
64 | src: ['test/**/*.html']
65 | },
66 | options: {
67 | log: true,
68 | logErrors: true
69 | }
70 | }
71 | });
72 |
73 | grunt.loadNpmTasks('grunt-babel');
74 | grunt.loadNpmTasks('grunt-contrib-concat');
75 | grunt.loadNpmTasks('grunt-contrib-uglify');
76 | grunt.loadNpmTasks('grunt-contrib-jshint');
77 | grunt.loadNpmTasks('grunt-jscs');
78 | grunt.loadNpmTasks('grunt-contrib-cssmin');
79 | grunt.loadNpmTasks('grunt-contrib-csslint');
80 | grunt.loadNpmTasks('grunt-mocha');
81 |
82 | grunt.registerTask('default', ['jshint', 'jscs', 'concat', 'babel', 'uglify', 'csslint', 'cssmin']);
83 | grunt.registerTask('test', ['jshint', 'jscs', 'concat', 'babel', 'uglify', 'csslint', 'cssmin', 'mocha']);
84 | };
85 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Harrison Kelly
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # d3-relationshipgraph [](https://travis-ci.org/hkelly93/d3-relationshipgraph) [](https://david-dm.org/hkelly93/d3-relationshipgraph.svg) [](https://david-dm.org/hkelly93/d3-relationshipgraph#info=devDependencies)
2 | A framework for creating parent-child relationships with [D3.js](http://www.d3js.org).
3 |
4 | ## Examples
5 | View a working example [here](https://cdn.rawgit.com/hkelly93/d3-relationshipGraph/master/examples/index.html).
6 |
7 | If you have used d3-relationshipgraph, feel free to edit this readme and put a link and image for your example.
8 |
9 | ## Installation
10 | You can install d3-relationshipgraph via [bower](http://bower.io)
11 |
12 | ```
13 | $ bower install d3-relationshipgraph
14 | ```
15 | You can also use [npm](http://npmjs.org)
16 |
17 | ```
18 | $ npm install d3-relationshipgraph
19 | ```
20 | Or by downloading the repository and running
21 | ```
22 | $ npm install
23 | ```
24 | in the directory.
25 |
26 | ## Usage
27 | ### Setup
28 | Since d3.relationshipgraph extends the D3.js framework, it can be easily added to an existing project by adding the following
29 |
30 | ```html
31 |
32 |
33 |
34 | ````
35 |
36 | Once the framework is added to the HTML file, graphs can be created using familiar D3 selections
37 |
38 | ```javascript
39 | var json = [
40 | {
41 | movietitle: 'Avatar',
42 | parent: '20th Century Fox',
43 | value: '$2,787,965,087',
44 | year: '2009'
45 | },
46 | {
47 | movietitle: 'Titanic',
48 | parent: '20th Century Fox',
49 | value: '$2,186,772,302',
50 | year: '1997'
51 | }
52 | ];
53 |
54 | var graph = d3.select('#graph').relationshipGraph({
55 | showTooltips: true,
56 | maxChildCount: 10,
57 | showKeys: false,
58 | thresholds: [1000000000, 2000000000, 3000000000]
59 | }).data(json);
60 | ```
61 |
62 | This simple code will produce the example at the beginning of the readme.
63 |
64 | ### Thresholds
65 | Thresholds can be `strings` or `numbers`. If you use a `string`, only values that match exactly will be in that threshold. If you use a number, a numeric value will be in the smallest threshold that is greater than the value.
66 | If the values are `strings` (such as in the example above), the number is extracted from the string and used. This allows you to use string values such as:
67 |
68 | ```javascript
69 | var json = [
70 | {parent: 'a', value: '$100'},
71 | {parent: 'b', value: '$100.15'},
72 | {parent: 'c', value: '100%'},
73 | {parent: 'd', value: '100.15%'}
74 | ];
75 | ````
76 |
77 | and thresholds such as:
78 |
79 | ```javascript
80 | var thresholds = [25, 50, 75, 100];
81 | ````
82 |
83 | ### Private Data
84 | Private data can be added to the JSON data by using the `_private_` key. This allows you to pass private data into the onClick function that isn't shown in the tooltip.
85 |
86 | To use private data, structure your JSON data so that it looks similar to
87 |
88 | ```javascript
89 | var myData = {
90 | parent: 'parentA',
91 | name: 'child1',
92 | _private_: {
93 | private1: 'Hidden from the tooltip.',
94 | private2: 'Also hidden from the tooltip.'
95 | }
96 | }
97 | ```
98 |
99 | ### Configuration
100 | d3.relationshipgraph is configured by passing in a JavaScript object into the constructor. The object can have the following properties
101 |
102 | ```Javascript
103 | config = {
104 | showTooltips: true, // Whether or not to show tooltips when the child block is moused over.
105 | maxChildCount: 10, // The maximum amount of children to show per row before wrapping.
106 | onClick: function(obj) {}, // The callback function to call when a child block is clicked on. This gets passed the JSON for the object.
107 | showKeys: true, // Whether or not to show the JSON keys in the tooltip
108 | thresholds: [100, 200, 300], // The thresholds for the color changes. If the values are strings, the colors are determined by the value of the child being equal to the threshold. If the thresholds are numbers, the color is determined by the value being less than the threshold.
109 | colors: ['red', 'green', 'blue'], // The custom color set to use for the child blocks. These can be color names, HEX values, or RGBA values.
110 | transitionTime: 1000, // The time in milliseconds for the transitions. Set to 0 to disable.
111 | truncate: 25, // The maximum length for the parent labels before they get truncated. Set to 0 to disable.
112 | sortFunction: sortJson, // A custom sort function. The parent value must be sorted first.
113 | valueKeyName: 'Worldwide Gross' // Set a custom key value in the tooltip instead of showing 'value'.
114 | }
115 | ```
116 |
117 | None of the configurations are required and they all have default values
118 |
119 | ```Javascript
120 | config = {
121 | showTooltips: true,
122 | maxChildCount: 0, // When the value is 0, the max count is determined by the width of the parent element.
123 | onClick: function () { }, // no-op
124 | showKeys: true,
125 | thresholds: [], // All chiild blocks will be the same color.
126 | transitionTime: 1500,
127 | truncate: 0,
128 | sortFunction: sortJson,
129 | valueKeyName: 'value'
130 | }
131 | ```
132 |
133 | If a custom sorting is used, the `parent` value MUST be sorted first.
134 |
135 | ### Updating with New Data
136 | To update the relationship graph with new data, store the RelationshipGraph object and call the `data` function with the updated JSON
137 |
138 | ```Javascript
139 | var json = [
140 | {
141 | movietitle: 'Avatar',
142 | parent: '20th Century Fox',
143 | value: '$2,787,965,087',
144 | year: '2009'
145 | },
146 | {
147 | movietitle: 'Titanic',
148 | parent: '20th Century Fox',
149 | value: '$2,186,772,302',
150 | year: '1997'
151 | }
152 | ];
153 |
154 | var graph = d3.select('#graph').relationshipGraph({
155 | showTooltips: true,
156 | maxChildCount: 10,
157 | showKeys: false,
158 | thresholds: [1000000000, 2000000000, 3000000000]
159 | });
160 |
161 | graph.data(json); // Add the first set of data.
162 |
163 | json = [
164 | {
165 | movietitle: 'Avatar',
166 | parent: '20th Century Fox',
167 | value: '$2,787,965,087',
168 | year: '2009'
169 | },
170 | {
171 | movietitle: 'Titanic',
172 | parent: '20th Century Fox',
173 | value: '$2,186,772,302',
174 | year: '1997'
175 | },
176 | {
177 | movietitle: 'Star Wars: The Force Awakens',
178 | parent: 'Walt Disney Studios',
179 | value: '$2,066,247,462',
180 | year: '2015'
181 | }
182 | ];
183 |
184 | graph.data(json); // Update the graph with new data.
185 | ````
186 |
187 | ## Child Node Interaction
188 | To interact with the child nodes once they are in the graph, you can query for them based on subobjects. Thiswill return the objects that match the query. Once these objects have been returned,
189 | you can change the color of the nodes by using the `setNodeColor` method on the object, or change the stroke color of the node by using the `setNodeStrokeColor` method.
190 |
191 | An example of a query is if I was lookingfor all nodes in the following example that are from the year 2009
192 |
193 | ```javascript
194 | var json = [
195 | {
196 | movietitle: 'Avatar',
197 | parent: '20th Century Fox',
198 | value: '$2,787,965,087',
199 | year: '2009'
200 | },
201 | {
202 | movietitle: 'Titanic',
203 | parent: '20th Century Fox',
204 | value: '$2,186,772,302',
205 | year: '1997'
206 | }
207 | ];
208 |
209 | var graph = d3.select('#graph').relationshipGraph();
210 |
211 | graph.query({year: '2009'});
212 | ```
213 | That would return the Javascript object(s) that match the query.
214 |
215 | ## License
216 | This project is licensed under the MIT license -- see the [LICENSE.md](LICENSE.md) file for details.
217 |
218 | ## Contributing
219 | If you would like to contribute please ensure that the following passes
220 |
221 | ```
222 | $ grunt test -v
223 | ```
224 | before putting up a pull request.
225 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "d3-relationshipgraph",
3 | "description": "A D3 graph to show parent child relationships.",
4 | "main": "src/d3-tip.js, src/index.js",
5 | "dependencies": {
6 | "d3": "^4.0.1"
7 | },
8 | "devDependencies": {
9 | "babel-preset-es2015": "^6.9.0",
10 | "chai": "~3.5.0",
11 | "mocha": "~2.5.3",
12 | "grunt": "^1.0.1",
13 | "grunt-babel": "^6.0.0",
14 | "grunt-contrib-concat": "^1.0.1",
15 | "grunt-contrib-csslint": "^1.0.0",
16 | "grunt-contrib-cssmin": "^1.0.1",
17 | "grunt-contrib-jshint": "^1.0.0",
18 | "grunt-contrib-uglify": "^1.0.1",
19 | "grunt-jscs": "^3.0.0",
20 | "grunt-mocha": "^1.0.2"
21 | },
22 | "version": "2.0.0",
23 | "keywords": [
24 | "d3",
25 | "relationship",
26 | "graph",
27 | "parent",
28 | "child",
29 | "relationshipgraph",
30 | "d3.relationshipgraph"
31 | ],
32 | "authors": "Harrison Kelly ",
33 | "license": "MIT"
34 | }
35 |
--------------------------------------------------------------------------------
/d3.relationshipgraph.min.js:
--------------------------------------------------------------------------------
1 | (function(root,factory){"use strict";if(typeof define==="function"&&define.amd){define(["d3"],factory)}else if(typeof module==="object"&&module.exports){module.exports=function(d3){d3.tip=factory(d3);return d3.tip}}else{root.d3.tip=factory(root.d3)}})(this,function(d3){"use strict";return function(){var direction=d3_tip_direction,offset=d3_tip_offset,html=d3_tip_html,node=initNode(),svg=null,point=null,target=null;var getPageTopLeft=function(el){var rect=el.getBoundingClientRect();var docEl=document.documentElement;return{top:rect.top+(window.pageYOffset||docEl.scrollTop||0),right:rect.right+(window.pageXOffset||0),bottom:rect.bottom+(window.pageYOffset||0),left:rect.left+(window.pageXOffset||docEl.scrollLeft||0)}};function tip(vis){svg=getSVGNode(vis);point=svg.createSVGPoint();document.body.appendChild(node)}tip.show=function(){var args=Array.prototype.slice.call(arguments);if(args[args.length-1]instanceof SVGElement){target=args.pop()}var content=html.apply(this,args),poffset=offset.apply(this,args),dir=direction.apply(this,args),nodel=getNodeEl(),i=directions.length,coords,scrollTop=document.documentElement.scrollTop||document.body.scrollTop,scrollLeft=document.documentElement.scrollLeft||document.body.scrollLeft;nodel.html(content).style({opacity:1,"pointer-events":"all"});var node=nodel[0][0],nodeWidth=node.clientWidth,nodeHeight=node.clientHeight,windowWidth=window.innerWidth,windowHeight=window.innerHeight,elementCoords=getPageTopLeft(this),breaksTop=elementCoords.top-nodeHeight<0,breaksLeft=elementCoords.left-nodeWidth<0,breaksRight=elementCoords.right+nodeHeight>windowWidth,breaksBottom=elementCoords.bottom+nodeHeight>windowHeight;if(breaksTop&&!breaksRight&&!breaksBottom&&breaksLeft){dir="e"}else if(breaksTop&&!breaksRight&&!breaksBottom&&!breaksLeft){dir="s"}else if(breaksTop&&breaksRight&&!breaksBottom&&!breaksLeft){dir="w"}else if(!breaksTop&&!breaksRight&&!breaksBottom&&breaksLeft){dir="e"}else if(!breaksTop&&!breaksRight&&breaksBottom&&breaksLeft){dir="e"}else if(!breaksTop&&!breaksRight&&breaksBottom&&!breaksLeft){dir="e"}else if(!breaksTop&&breaksRight&&breaksBottom&&!breaksLeft){dir="n"}else if(!breaksTop&&breaksRight&&!breaksBottom&&!breaksLeft){dir="w"}direction(dir);while(i--){nodel.classed(directions[i],false)}coords=direction_callbacks.get(dir).apply(this);nodel.classed(dir,true).style({top:coords.top+poffset[0]+scrollTop+"px",left:coords.left+poffset[1]+scrollLeft+"px"});return tip};tip.hide=function(){var nodel=getNodeEl();nodel.style({opacity:0,"pointer-events":"none"});return tip};tip.attr=function(n){if(arguments.length<2&&typeof n==="string"){return getNodeEl().attr(n)}else{var args=Array.prototype.slice.call(arguments);d3.selection.prototype.attr.apply(getNodeEl(),args)}return tip};tip.style=function(n,v){if(arguments.length<2&&typeof n==="string"){return getNodeEl().style(n)}else{var args=Array.prototype.slice.call(arguments);d3.selection.prototype.style.apply(getNodeEl(),args)}return tip};tip.direction=function(v){if(!arguments.length){return direction}direction=v==null?v:d3.functor(v);return tip};tip.offset=function(v){if(!arguments.length){return offset}offset=v==null?v:d3.functor(v);return tip};tip.html=function(v){if(!arguments.length){return html}html=v==null?v:d3.functor(v);return tip};tip.destroy=function(){if(node){getNodeEl().remove();node=null}return tip};function d3_tip_direction(){return"n"}function d3_tip_offset(){return[0,0]}function d3_tip_html(){return" "}var direction_callbacks=d3.map({n:direction_n,s:direction_s,e:direction_e,w:direction_w,nw:direction_nw,ne:direction_ne,sw:direction_sw,se:direction_se}),directions=direction_callbacks.keys();function direction_n(){var bbox=getScreenBBox();return{top:bbox.n.y-node.offsetHeight,left:bbox.n.x-node.offsetWidth/2}}function direction_s(){var bbox=getScreenBBox();return{top:bbox.s.y,left:bbox.s.x-node.offsetWidth/2}}function direction_e(){var bbox=getScreenBBox();return{top:bbox.e.y-node.offsetHeight/2,left:bbox.e.x}}function direction_w(){var bbox=getScreenBBox();return{top:bbox.w.y-node.offsetHeight/2,left:bbox.w.x-node.offsetWidth}}function direction_nw(){var bbox=getScreenBBox();return{top:bbox.nw.y-node.offsetHeight,left:bbox.nw.x-node.offsetWidth}}function direction_ne(){var bbox=getScreenBBox();return{top:bbox.ne.y-node.offsetHeight,left:bbox.ne.x}}function direction_sw(){var bbox=getScreenBBox();return{top:bbox.sw.y,left:bbox.sw.x-node.offsetWidth}}function direction_se(){var bbox=getScreenBBox();return{top:bbox.se.y,left:bbox.e.x}}function initNode(){var node=d3.select(document.createElement("div"));node.style({position:"absolute",top:0,opacity:0,"pointer-events":"none","box-sizing":"border-box"});return node.node()}function getSVGNode(el){el=el.node();if(el.tagName.toLowerCase()==="svg"){return el}return el.ownerSVGElement}function getNodeEl(){if(node===null){node=initNode();document.body.appendChild(node)}return d3.select(node)}function getScreenBBox(){var targetel=target||d3.event.target;while("undefined"===typeof targetel.getScreenCTM&&"undefined"===targetel.parentNode){targetel=targetel.parentNode}var bbox={},matrix=targetel.getScreenCTM(),tbbox=targetel.getBBox(),width=tbbox.width,height=tbbox.height,x=tbbox.x,y=tbbox.y;point.x=x;point.y=y;bbox.nw=point.matrixTransform(matrix);point.x+=width;bbox.ne=point.matrixTransform(matrix);point.y+=height;bbox.se=point.matrixTransform(matrix);point.x-=width;bbox.sw=point.matrixTransform(matrix);point.y-=height/2;bbox.w=point.matrixTransform(matrix);point.x+=width;bbox.e=point.matrixTransform(matrix);point.x-=width/2;point.y-=height/2;bbox.n=point.matrixTransform(matrix);point.y+=height;bbox.s=point.matrixTransform(matrix);return bbox}return tip}});(function(root,factory){"use strict";if(typeof define==="function"&&define.amd){define("d3.relationshipGraph",["d3"],factory)}else if(typeof exports==="object"&&typeof module==="object"){module.exports=factory(require("d3"))}else if(typeof exports==="object"){exports.d3.relationshipGraph=factory(require("d3"))}else{root.d3.relationshipGraph=factory(root.d3)}})(this,function(d3){"use strict";var containsKey=function(obj,key){return Object.keys(obj).indexOf(key)>-1};var contains=function(arr,key){return arr.indexOf(key)>-1};var truncate=function(str,cap){if(cap===0){return str}return str.length>=cap?str.substring(0,cap)+"...":str};var noop=function(){};d3.relationshipGraph=function(){return RelationshipGraph.extend.apply(RelationshipGraph,arguments)};d3.selection.prototype.relationshipGraph=function(userConfig){return new RelationshipGraph(this,userConfig)};d3.selection.enter.prototype.relationshipGraph=function(){return this.graph};var RelationshipGraph=function(selection,userConfig){if(userConfig.thresholds===undefined||typeof userConfig.thresholds!=="object"){throw"Thresholds must be an Object."}this.config={blockSize:24,selection:selection,showTooltips:userConfig.showTooltips||true,maxChildCount:userConfig.maxChildCount||0,onClick:userConfig.onClick||noop,showKeys:userConfig.showKeys||true,thresholds:userConfig.thresholds,colors:userConfig.colors||["#c4f1be","#a2c3a4","#869d96","#525b76","#201e50","#485447","#5b7f77","#6474ad","#b9c6cb","#c0d6c1","#754668","#587d71","#4daa57","#b5dda4","#f9eccc","#0e7c7b","#17bebb","#d4f4dd","#d62246","#4b1d3f","#cf4799","#c42583","#731451","#f3d1bf","#c77745"],transitionTime:userConfig.transitionTime||1500,truncate:userConfig.truncate||25};if(this.config.thresholds.length>0&&typeof this.config.thresholds[0]=="number"){this.config.thresholds.sort()}this.ctx=document.createElement("canvas").getContext("2d");this.ctx.font="10pt Helvetica";var createTooltip=function(self){var hiddenKeys=["ROW","INDEX","COLOR","PARENTCOLOR","PARENT"],showKeys=self.config.showKeys;return d3.tip().attr("class","relationshipGraph-tip").offset([-8,-10]).html(function(obj){var keys=Object.keys(obj),table=document.createElement("table"),count=keys.length,rows=[];while(count--){var element=keys[count],upperCaseKey=element.toUpperCase();if(!contains(hiddenKeys,upperCaseKey)){var row=document.createElement("tr"),key=showKeys?document.createElement("td"):null,value=document.createElement("td");if(showKeys){key.innerHTML=element.charAt(0).toUpperCase()+element.substring(1);row.appendChild(key)}value.innerHTML=obj[element];value.style.fontWeight="normal";row.appendChild(value);rows.push(row)}}var rowCount=rows.length;while(rowCount--){table.appendChild(rows[rowCount])}self.tip.direction("n");return table.outerHTML})};if(this.config.showTooltips){this.tip=createTooltip(this)}else{this.tip=null}this.svg=this.config.selection.select("svg").select("g");if(this.svg.empty()){this.svg=this.config.selection.append("svg").attr("width","500").attr("height","500").attr("style","display: block").append("g").attr("transform","translate(10, 0)")}this.graph=this};RelationshipGraph.prototype.verifyJson=function(json){if(json===undefined||typeof JSON!=="object"||json.length===0){throw"JSON has to be a JavaScript object that is not empty."}var length=json.length;while(length--){var element=json[length],keys=Object.keys(element),keyLength=keys.length;if(element.parent===undefined){throw"Child does not have a parent."}else if(element.parentColor!==undefined&&(element.parentColor>4||element.parentColor<0)){throw"Parent color is unsupported."}while(keyLength--){if(keys[keyLength].toUpperCase()=="VALUE"){if(keys[keyLength]!="value"){json[length].value=json[length][keys[keyLength]];delete json[length][keys[keyLength]]}break}}}return true};RelationshipGraph.prototype.data=function(json){if(this.verifyJson(json)){var row=1,index=1,previousParent=null,parents=[],parentSizes={},previousParentSizes=0,_this=this,parent,i,maxWidth,maxHeight;json.sort(function(child1,child2){if(child1.parentchild2.parent){return 1}else{return 0}});for(i=0;ilongest.length){longest=current}}var longestWidth=this.ctx.measureText(longest).width,parentDiv=this.config.selection[0][0],calculatedMaxChildren=this.config.maxChildCount===0?Math.floor((parentDiv.parentElement.clientWidth-15-longestWidth)/this.config.blockSize):this.config.maxChildCount;for(i=0;i-1){previousParentSize+=Math.ceil(parentSizes[Object.keys(parentSizes)[i]]/calculatedMaxChildren)*calculatedMaxChildren;i--}return Math.ceil(previousParentSize/calculatedMaxChildren)*_this.config.blockSize}).style("fill",function(obj){return obj.parentColor!==undefined?_this.config.colors[obj.parentColor]:"#000000"});parentNodes.exit().remove();var childrenNodes=this.svg.selectAll(".relationshipGraph-block").data(json);childrenNodes.enter().append("rect").attr("x",function(obj){return longestWidth+(obj.index-1)*_this.config.blockSize}).attr("y",function(obj){return(obj.row-1)*_this.config.blockSize}).attr("rx",4).attr("ry",4).attr("class","relationshipGraph-block").attr("width",_this.config.blockSize).attr("height",_this.config.blockSize).style("fill",function(obj){return _this.config.colors[obj.color%_this.config.colors.length]||_this.config.colors[0]}).on("mouseover",_this.tip?_this.tip.show:noop).on("mouseout",_this.tip?_this.tip.hide:noop).on("click",function(obj){_this.tip.hide();_this.config.onClick(obj)});childrenNodes.transition(_this.config.transitionTime).attr("x",function(obj){return longestWidth+(obj.index-1)*_this.config.blockSize}).attr("y",function(obj){return(obj.row-1)*_this.config.blockSize}).style("fill",function(obj){return _this.config.colors[obj.color%_this.config.colors.length]||_this.config.colors[0]});childrenNodes.exit().transition(_this.config.transitionTime).remove();if(this.config.showTooltips){d3.select(".d3-tip").remove();this.svg.call(this.tip)}this.config.selection.select("svg").attr("width",maxWidth+15).attr("height",maxHeight+15)}return this};return RelationshipGraph});
--------------------------------------------------------------------------------
/dest/d3.relationshipgraph.min.css:
--------------------------------------------------------------------------------
1 | .relationshipGraph-block{stroke:#F7F7F7;stroke-width:1px;pointer-events:all}.relationshipGraph-block:hover{cursor:pointer}.relationshipGraph-Text{font-family:Helvetica,sans-serif;font-size:10pt;fill:#323232}.relationshipGraph-measurement{font-family:Helvetica,sans-serif;font-size:13px;position:absolute;width:auto;height:auto;left:-100%;top:-100%}.relationshipGraph-tip{font-weight:700;font-family:Helvetica,sans-serif;font-size:9pt;line-height:1;padding:12px;background:#323232;color:#e7e7e7;border-radius:6px;z-index:50;max-width:350px;max-height:300px}.relationshipGraph-tip:after{display:inline-block;font-size:15px;width:100%;height:5px;color:#323232;content:"\25B6";position:absolute}.relationshipGraph-tip.n:after{content:"\25BC";margin:-1px 0 0;top:100%;left:12px;text-align:center}.relationshipGraph-tip.e{margin-left:15px}.relationshipGraph-tip.e:after{content:"\25C0";margin:-2px 0 0;top:50%;left:-11px}.relationshipGraph-tip.s{margin-top:15px}.relationshipGraph-tip.s:after{content:"\25B2";margin:0 0 1px;top:-12px;left:12px;text-align:center}.relationshipGraph-tip.w:after{content:"\25B6";margin:-4px 0 0 -1px;top:50%;left:100%}
--------------------------------------------------------------------------------
/dest/d3.relationshipgraph.min.js:
--------------------------------------------------------------------------------
1 | "use strict";function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[],_n=!0,_d=!1,_e=void 0;try{for(var _s,_i=arr[Symbol.iterator]();!(_n=(_s=_i.next()).done)&&(_arr.push(_s.value),!i||_arr.length!==i);_n=!0);}catch(err){_d=!0,_e=err}finally{try{!_n&&_i["return"]&&_i["return"]()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr))return arr;if(Symbol.iterator in Object(arr))return sliceIterator(arr,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass=function(){function defineProperties(target,props){for(var i=0;iwindowWidth,breaksBottom=elementCoords.bottom+nodeHeight>windowHeight;for(breaksTop&&!breaksRight&&!breaksBottom&&breaksLeft?dir="e":!breaksTop||breaksRight||breaksBottom||breaksLeft?breaksTop&&breaksRight&&!breaksBottom&&!breaksLeft?dir="w":breaksTop||breaksRight||breaksBottom||!breaksLeft?!breaksTop&&!breaksRight&&breaksBottom&&breaksLeft?dir="e":breaksTop||breaksRight||!breaksBottom||breaksLeft?!breaksTop&&breaksRight&&breaksBottom&&!breaksLeft?dir="n":breaksTop||!breaksRight||breaksBottom||breaksLeft||(dir="w"):dir="e":dir="e":dir="s",direction(dir);i--;)nodel.classed(directions[i],!1);return coords=direction_callbacks.get(dir).apply(this),nodel.classed(dir,!0).style("top",coords.top+poffset[0]+scrollTop+"px").style("left",coords.left+poffset[1]+scrollLeft+"px"),tip},tip.hide=function(){var nodel=getNodeEl();return nodel.style("opacity",0).style("pointer-events","none"),tip},tip.attr=function(n){if(arguments.length<2&&"string"==typeof n)return getNodeEl().attr(n);var args=Array.prototype.slice.call(arguments);return d3.selection.prototype.attr.apply(getNodeEl(),args),tip},tip.style=function(n){if(arguments.length<2&&"string"==typeof n)return getNodeEl().style(n);var args=Array.prototype.slice.call(arguments);if(1===args.length)for(var styles=args[0],keys=Object.keys(styles),key=0;keyi;i++){var current=parents[i]+" ( "+parentSizes[parentNames[i]]+") ";current.length>longest.length&&(longest=current)}var longestWidth=this.getPixelLength(longest),parentDiv=this._d3V4?selection._groups[0][0]:selection[0][0],calculatedMaxChildren=0===configuration.maxChildCount?Math.floor((parentDiv.parentElement.clientWidth-blockSize-longestWidth)/blockSize):configuration.maxChildCount,jsonLength=json.length,thresholds=configuration.thresholds;for(i=0;jsonLength>i;i++){var element=json[i],parent=element.parent;if(null!==previousParent&&previousParent!==parent?(element.__row=row+1,element.__index=1,index=2,row++):(index===calculatedMaxChildren+1&&(index=1,row++),element.__row=row,element.__index=index,index++),previousParent=parent,0===thresholds.length)element.__color=0;else{var value=void 0,compare=void 0;if("string"==typeof thresholds[0])value=element.value,compare=RelationshipGraph.stringCompare;else{var elementValue=element.value;value="number"==typeof elementValue?elementValue:parseFloat(elementValue.replace(/[^0-9-.]+/g,"")),compare=RelationshipGraph.numericCompare}var thresholdIndex=compare(value,thresholds);element.__color=-1===thresholdIndex?0:thresholdIndex,element.__colorValue=this.configuration.colors[element.__color%this.configuration.colors.length]}element.setNodeColor=function(color){this.__node||(this.__node=document.getElementById(this.__id)),this.__node&&(this.__node.style.fill=color)},element.setNodeStrokeColor=function(color){this.__node||(this.__node=document.getElementById(this.__id)),this.__node&&(this.__node.style.strokeWidth=color?"1px":0,this.__node.style.stroke=color?color:"")},element.__id=this.getId()+"-child-node"+element.__row+"-"+element.__index}return[longestWidth,calculatedMaxChildren,row]}},{key:"createParents",value:function(parentNodes,parentSizes,longestWidth,calculatedMaxChildren){var parentSizesKeys=Object.keys(parentSizes),_this=this;parentNodes.enter().append("text").text(function(obj,index){return obj+" ("+parentSizes[parentSizesKeys[index]]+")"}).attr("x",function(obj,index){var width=_this.getPixelLength(obj+" ("+parentSizes[parentSizesKeys[index]]+")");return longestWidth-width}).attr("y",function(obj,index){if(0===index)return 0;for(var previousParentSize=0,i=index-1;i>-1;)previousParentSize+=Math.ceil(parentSizes[parentSizesKeys[i]]/calculatedMaxChildren)*calculatedMaxChildren,i--;return Math.ceil(previousParentSize/calculatedMaxChildren)*_this.configuration.blockSize+_this._spacing*index}).style("text-anchor","start").style("fill",function(obj){return void 0!==obj.parentColor?_this.configuration.colors[obj.parentColor]:"#000000"}).style("cursor",this.parentPointer?"pointer":"default").attr("class","relationshipGraph-Text").attr("transform","translate(-6, "+_this.configuration.blockSize/1.5+")").on("click",function(obj){_this.configuration.onClick.parent(obj)})}},{key:"updateParents",value:function(parentNodes,parentSizes,longestWidth,calculatedMaxChildren){var parentSizesKeys=Object.keys(parentSizes),_this=this;parentNodes.text(function(obj,index){return obj+" ("+parentSizes[parentSizesKeys[index]]+")"}).attr("x",function(obj,index){var width=_this.getPixelLength(obj+" ("+parentSizes[parentSizesKeys[index]]+")");return longestWidth-width}).attr("y",function(obj,index){if(0===index)return 0;for(var previousParentSize=0,i=index-1;i>-1;)previousParentSize+=Math.ceil(parentSizes[parentSizesKeys[i]]/calculatedMaxChildren)*calculatedMaxChildren,i--;return Math.ceil(previousParentSize/calculatedMaxChildren)*_this.configuration.blockSize+_this._spacing*index}).style("fill",function(obj){return void 0!==obj.parentColor?_this.configuration.colors[obj.parentColor]:"#000000"}).style("cursor",_this.parentPointer?"pointer":"default")}},{key:"createChildren",value:function(childrenNodes,longestWidth){var _this=this;childrenNodes.enter().append("rect").attr("id",function(obj){return obj.__id}).attr("x",function(obj){return longestWidth+(obj.__index-1)*_this.configuration.blockSize+5+(_this._spacing*obj.__index-1)}).attr("y",function(obj){return(obj.__row-1)*_this.configuration.blockSize+(_this._spacing*obj.__row-1)}).attr("rx",4).attr("ry",4).attr("class","relationshipGraph-block").attr("width",_this.configuration.blockSize).attr("height",_this.configuration.blockSize).style("fill",function(obj){return obj.__colorValue}).style("cursor",_this.childPointer?"pointer":"default").on("mouseover",_this.tooltip?_this.tooltip.show:RelationshipGraph.noop).on("mouseout",_this.tooltip?_this.tooltip.hide:RelationshipGraph.noop).on("click",function(obj){_this.tooltip.hide(),_this.configuration.onClick.child(obj)})}},{key:"updateChildren",value:function(childrenNodes,longestWidth){var blockSize=this.configuration.blockSize,_this=this;childrenNodes.transition(this.configuration.transitionTime).attr("id",function(obj){return obj.__id}).attr("x",function(obj){return longestWidth+(obj.__index-1)*blockSize+5+(_this._spacing*obj.__index-1)}).attr("y",function(obj){return(obj.__row-1)*blockSize+(_this._spacing*obj.__row-1)}).style("fill",function(obj){return obj.__colorValue})}},{key:"removeNodes",value:function(nodes){nodes.exit().transition(this.configuration.transitionTime).remove()}},{key:"data",value:function(json){if(RelationshipGraph.verifyJson(json)){var parents=[],parentSizes={},configuration=this.configuration,row=0,parent=void 0,i=void 0,maxWidth=void 0,maxHeight=void 0,calculatedMaxChildren=0,longestWidth=0;configuration.sortFunction(json),this.representation=json;var jsonLength=json.length;for(i=0;jsonLength>i;i++)parent=json[i].parent,RelationshipGraph.containsKey(parentSizes,parent)?parentSizes[parent]++:(parentSizes[parent]=1,parents.push(RelationshipGraph.truncate(parent,configuration.truncate)));var _assignIndexAndRow=this.assignIndexAndRow(json,parentSizes,parents),_assignIndexAndRow2=_slicedToArray(_assignIndexAndRow,3);for(longestWidth=_assignIndexAndRow2[0],calculatedMaxChildren=_assignIndexAndRow2[1],row=_assignIndexAndRow2[2],maxHeight=row*configuration.blockSize,maxWidth=longestWidth+calculatedMaxChildren*configuration.blockSize,maxWidth+=this._spacing*calculatedMaxChildren,i=0;row>i;i++)maxHeight+=this._spacing*i;var parentNodes=this.svg.selectAll(".relationshipGraph-Text").data(parents);this.createParents(parentNodes,parentSizes,longestWidth,calculatedMaxChildren),this.updateParents(parentNodes,parentSizes,longestWidth,calculatedMaxChildren),this.removeNodes(parentNodes);var childrenNodes=this.svg.selectAll(".relationshipGraph-block").data(json);this.createChildren(childrenNodes,longestWidth),this.updateChildren(childrenNodes,longestWidth),this.removeNodes(childrenNodes),this.configuration.showTooltips&&(d3.select(".d3-tip").remove(),this.svg.call(this.tooltip)),this.configuration.selection.select("svg").attr("width",Math.abs(maxWidth+15)).attr("height",Math.abs(maxHeight+15))}return this}},{key:"search",value:function(query){var results=[],queryKeys=Object.keys(query),queryKeysLength=queryKeys.length;if(this.representation&&query)for(var length=this.representation.length,i=0;length>i;i++){for(var currentObject=this.representation[i],isMatch=!1,j=0;queryKeysLength>j;j++){var queryVal=query[queryKeys[j]];if(!(isMatch=currentObject[queryKeys[j]]==queryVal))break}isMatch&&results.push(currentObject)}return results}}],[{key:"getColors",value:function(){return["#c4f1be","#a2c3a4","#869d96","#525b76","#201e50","#485447","#5b7f77","#6474ad","#b9c6cb","#c0d6c1","#754668","#587d71","#4daa57","#b5dda4","#f9eccc","#0e7c7b","#17bebb","#d4f4dd","#d62246","#4b1d3f","#cf4799","#c42583","#731451","#f3d1bf","#c77745"]}},{key:"containsKey",value:function(obj,key){return Object.keys(obj).indexOf(key)>-1}},{key:"contains",value:function(arr,key){return arr.indexOf(key)>-1}},{key:"truncate",value:function(str,cap){return cap&&str&&str.length>cap?str.substring(0,cap)+"...":str}},{key:"isArray",value:function(arr){return"[object Array]"==Object.prototype.toString.call(arr)}},{key:"noop",value:function(){}},{key:"sortJson",value:function(json){json.sort(function(child1,child2){var parent1=child1.parent.toLowerCase(),parent2=child2.parent.toLowerCase();return parent1>parent2?1:parent2>parent1?-1:0})}},{key:"stringCompare",value:function(value,thresholds){if("string"!=typeof value)throw"Cannot make value comparison between a string and a "+("undefined"==typeof value?"undefined":_typeof(value))+".";if(!thresholds||!thresholds.length)throw"Cannot find correct threshold because there are no thresholds.";for(var thresholdsLength=thresholds.length,i=0;thresholdsLength>i;i++)if(value==thresholds[i])return i;return-1}},{key:"numericCompare",value:function(value,thresholds){if("number"!=typeof value)throw"Cannot make value comparison between a number and a "+("undefined"==typeof value?"undefined":_typeof(value))+".";if(!thresholds||!thresholds.length)throw"Cannot find correct threshold because there are no thresholds.";for(var length=thresholds.length,i=0;length>i;i++)if(value<=thresholds[i])return i;return-1}},{key:"verifyJson",value:function(json){if(!RelationshipGraph.isArray(json)||json.length<0||"object"!==_typeof(json[0]))throw"JSON has to be an Array of JavaScript objects that is not empty.";for(var length=json.length;length--;){var element=json[length],keys=Object.keys(element),keyLength=keys.length,parentColor=element.parentColor;if(void 0===element.parent)throw"Child does not have a parent.";if(void 0!==parentColor&&(parentColor>4||0>parentColor))throw"Parent color is unsupported.";for(;keyLength--;)if("VALUE"==keys[keyLength].toUpperCase()){"value"!=keys[keyLength]&&(json[length].value=json[length][keys[keyLength]],delete json[length][keys[keyLength]]);break}}return!0}}]),RelationshipGraph}();d3.relationshipGraph=function(){return RelationshipGraph.extend.apply(RelationshipGraph,arguments)},d3.selection.prototype.relationshipGraph=function(userConfig){return new RelationshipGraph(this,userConfig)};
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | d3.relationshipgraph Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |