├── src ├── teardown.js ├── utils │ ├── logger.js │ ├── colors.js │ ├── units.js │ └── helpers.js ├── scene │ ├── controls.js │ ├── renderers.js │ ├── lights.js │ ├── materials.js │ ├── cameras.js │ ├── geometries.js │ └── groups.js ├── views │ ├── text.js │ ├── base.js │ ├── circle.js │ ├── line.js │ └── axis.js ├── init.js ├── setup.js ├── controller.js └── dependencies │ └── OrbitControls.js ├── package.json ├── .gitignore ├── assets └── style.css ├── Gruntfile.js ├── README.md └── examples ├── network.html ├── scatter_plot.html ├── scatter_plot_animation.html └── data ├── scatter.js └── network.js /src/teardown.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: teardown.js 4 | */ 5 | // Expose to global d3 6 | window.d3 = _d3; 7 | 8 | } 9 | return _this; 10 | 11 | })(); 12 | -------------------------------------------------------------------------------- /src/utils/logger.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: utils/logger.js 4 | */ 5 | 6 | var LOGGER = (function () { 7 | return { 8 | report: function (properties) { 9 | 10 | var output = _this.about.name + " : " + properties.message; 11 | 12 | if (properties.error) 13 | output = output + " : " + properties.error; 14 | 15 | console.error(output); 16 | } 17 | }; 18 | })(); 19 | -------------------------------------------------------------------------------- /src/scene/controls.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/controls.js 4 | */ 5 | 6 | var CONTROLS = (function () { 7 | 8 | return { 9 | Orbit: function (camera) { 10 | var controls = new THREE.OrbitControls( camera ); 11 | controls.rotateSpeed = 1.0; 12 | controls.zoomSpeed = 1.0; 13 | controls.damping = 0.2; 14 | controls.noZoom = true; 15 | controls.dynamicDampingFactor = 1.0; 16 | 17 | return controls; 18 | } 19 | } 20 | })(); 21 | -------------------------------------------------------------------------------- /src/scene/renderers.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/renderers.js 4 | */ 5 | 6 | var RENDERERS = (function () { 7 | return { 8 | DEFAULT: function (width, height) { 9 | 10 | var width = width || window.innerWidth, 11 | height = height || window.innerHeight; 12 | 13 | var renderer = new THREE.WebGLRenderer({'antialiasing': true}); 14 | renderer.setClearColor(0xffffff); 15 | renderer.setPixelRatio(window.devicePixelRatio); 16 | renderer.setSize(width, height) 17 | 18 | return renderer; 19 | } 20 | }; 21 | })(); 22 | 23 | -------------------------------------------------------------------------------- /src/views/text.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: views/text.js 4 | */ 5 | 6 | VIEW.text = function() { 7 | 8 | this.type = 'text'; 9 | this.meshes = []; 10 | 11 | this.load = function(text){ 12 | 13 | var offsetX = UNITS.normalizeH(text.x, this.properties.canvas), 14 | offsetY = UNITS.normalizeV(text.y, this.properties.canvas), 15 | rotation = UNITS.extractRotation(text.transform); 16 | 17 | if (! rotation) 18 | offsetX -= text.length; 19 | 20 | this.meshes.push(GEOMETRIES.TEXT({ x: offsetX, y: offsetY, z: 0, text: text.val})); 21 | } 22 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3to3", 3 | "version": "0.9.0", 4 | "description": "Transform two-dimension D3.js graphs to three-dimensional using Three.js", 5 | "author": "emiliosnic", 6 | "scripts": { 7 | "start": "grunt" 8 | }, 9 | "keywords": [ 10 | "d3" 11 | ], 12 | "licenses": [ 13 | { 14 | "type": "MIT" 15 | } 16 | ], 17 | "dependencies": {}, 18 | "devDependencies": { 19 | "grunt": "^0.4.5", 20 | "grunt-contrib-concat": "^0.5.1", 21 | "grunt-contrib-uglify": "^0.9.1", 22 | "grunt-contrib-watch": "^0.6.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/scene/lights.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/lights.js 4 | */ 5 | 6 | var LIGHTS = (function () { 7 | 8 | var zDepth = 1; 9 | 10 | /** 11 | * Align light to given position 12 | */ 13 | 14 | _alignToPosition = function(position){ 15 | this 16 | .position 17 | .set( position.x, position.y, position.z - zDepth) 18 | .normalize(); 19 | } 20 | 21 | return { 22 | DEFAULT: function () { 23 | var light = new THREE.DirectionalLight(0xffffff); 24 | light.position.set(0,0,zDepth).normalize(); 25 | light.alignToPosition = _alignToPosition; 26 | 27 | return light; 28 | } 29 | }; 30 | })(); 31 | 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /src/scene/materials.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/materials.js 4 | */ 5 | 6 | var MATERIALS = (function () { 7 | 8 | return { 9 | DEFAULT_3D: function (color) { 10 | return (new THREE.MeshPhongMaterial({ 11 | color : COLORS.normalize(color), 12 | specular : 0x494949, 13 | emmisive : 0xffffff, 14 | shininess: 10 15 | })); 16 | }, 17 | DEFAULT_2D: function (color) { 18 | return (new THREE.MeshBasicMaterial({ 'color': COLORS.normalize(color)})); 19 | }, 20 | LINE: function (color, thickness) { 21 | return (new THREE.LineBasicMaterial({ 'color': COLORS.normalize(color), 'linewidth': thickness})); 22 | }, 23 | AXIS: function (color) { 24 | return (new THREE.LineBasicMaterial({ 'color': COLORS.normalize(color)})); 25 | } 26 | }; 27 | })(); 28 | 29 | -------------------------------------------------------------------------------- /assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 0.7em; 3 | background: #FFF; 4 | font-family: 'Lato'; 5 | text-align: center; 6 | } 7 | 8 | .axis path, .axis line { 9 | fill: none; 10 | stroke: #000; 11 | } 12 | 13 | .panels { 14 | display: block; 15 | width: 100%; 16 | height: auto; 17 | overflow: auto; 18 | padding: 0; 19 | margin: 0; 20 | } 21 | 22 | .panels li { 23 | display: block; 24 | width: 50%; 25 | padding: 20px; 26 | box-sizing: border-box; 27 | min-height: 350px; 28 | height: auto; 29 | overflow: auto; 30 | float: left; 31 | text-align: center; 32 | background: white; 33 | } 34 | 35 | .panels li h2 { 36 | font-size: 1.5em; 37 | padding: 20px 0; 38 | } 39 | 40 | #code_panel { 41 | width: 90%; 42 | height: 400px; 43 | overflow: auto; 44 | display: inline-block; 45 | font-size: 0.8em; 46 | background: #282828; 47 | color: white; 48 | } 49 | -------------------------------------------------------------------------------- /src/utils/colors.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: utils/colors.js 4 | */ 5 | 6 | var COLORS = (function () { 7 | 8 | /** 9 | * Convery component to HEX 10 | */ 11 | 12 | _componentToHex = function(c) { 13 | var hex = c.toString(16); 14 | return hex.length == 1 ? "0" + hex : hex; 15 | } 16 | 17 | return { 18 | normalize: function (input) { 19 | 20 | if (input == undefined || typeof input !== "string" || input == 'default') 21 | return "#000000"; 22 | 23 | if (input.charAt(0) === '#') { 24 | return ((input.length > 6 )? input.substring(0,7):input); 25 | 26 | } else { 27 | 28 | var rgb = /\(([^)]+)\)/.exec(input)[1].split(','); 29 | var r = parseInt(rgb[0]), 30 | g = parseInt(rgb[1]), 31 | b = parseInt(rgb[2]); 32 | 33 | return "#" + _componentToHex(r) + _componentToHex(g) + _componentToHex(b); 34 | } 35 | } 36 | }; 37 | })(); 38 | -------------------------------------------------------------------------------- /src/views/base.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: views/base.js 4 | */ 5 | 6 | function VIEW(){}; 7 | 8 | VIEW.prototype.type = function(type){ 9 | var constr = type; 10 | 11 | if (typeof VIEW[constr] !== "function"){ 12 | LOGGER.report({'message': ('Failed to construct VIEW - Caller '+arguments.callee.caller.name)}); 13 | } 14 | if (typeof VIEW[constr].prototype.type !== "function") { 15 | VIEW[constr].prototype = new VIEW(); 16 | } 17 | return new VIEW[constr](); 18 | } 19 | 20 | VIEW.prototype.setProperties = function(properties) { 21 | this.properties = properties; 22 | return this; 23 | }; 24 | 25 | VIEW.prototype.loadData = function(data) { 26 | this.load(data); 27 | return this; 28 | }; 29 | 30 | VIEW.prototype.appendTo = function(group) { 31 | 32 | if (group && group instanceof THREE.Group){ 33 | this.meshes.forEach(function(item){ 34 | item.userData.parent = group; 35 | group.add(item); 36 | }) 37 | } 38 | VIEW.meshes = []; 39 | 40 | return this; 41 | }; 42 | -------------------------------------------------------------------------------- /src/views/circle.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: views/circle.js 4 | */ 5 | 6 | VIEW.circle = function() { 7 | 8 | this.type = 'circle'; 9 | this.meshes = []; 10 | 11 | this.load = function(data){ 12 | 13 | var that = this; 14 | 15 | data.forEach(function (item) { 16 | var radius = item.r.baseVal.value, 17 | offsetX = item.cx.baseVal.value, 18 | offsetY = item.cy.baseVal.value, 19 | color = COLORS.normalize(item.style.cssText.slice(6)); 20 | 21 | var x = UNITS.normalizeH(offsetX, that.properties.canvas), 22 | y = UNITS.normalizeV(offsetY, that.properties.canvas); 23 | 24 | if (that.properties['3D']){ 25 | /* 26 | * 3D View 27 | */ 28 | that.meshes.push(GEOMETRIES.SPHERE({ radius: radius, color: color, x: x, y: y, z: 0})); 29 | 30 | } else { 31 | /* 32 | * 2D View 33 | */ 34 | var circle = GEOMETRIES.CIRCLE({ radius: radius, color: color, x: x, y: y, z: 0}); 35 | that.meshes.push(circle); 36 | } 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/views/line.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: views/line.js 4 | */ 5 | 6 | VIEW.line = function() { 7 | 8 | this.type = 'line'; 9 | this.meshes = []; 10 | 11 | this.load = function(data){ 12 | 13 | var that = this; 14 | 15 | data.forEach(function (item) { 16 | 17 | var attributes = item.extractNode('attributes'), 18 | x1_base = attributes.extractNode('x1').nodeValue, 19 | x2_base = attributes.extractNode('x2').nodeValue, 20 | y1_base = attributes.extractNode('y1').nodeValue, 21 | y2_base = attributes.extractNode('y2').nodeValue, 22 | thickness_style = attributes.extractNode('style').nodeValue; 23 | 24 | var x1 = UNITS.normalizeH(x1_base, that.properties.canvas), 25 | x2 = UNITS.normalizeH(x2_base, that.properties.canvas), 26 | y1 = UNITS.normalizeV(y1_base, that.properties.canvas), 27 | y2 = UNITS.normalizeV(y2_base, that.properties.canvas), 28 | thickness = 2 * UNITS.extractThickness(thickness_style); 29 | 30 | 31 | // Setup default parameters 32 | var lineColor = 0x000000; 33 | 34 | // Update with external style (if any) 35 | if ( that.properties.style 36 | && that.properties.style[that.type] 37 | && that.properties.style[that.type].color){ 38 | 39 | lineColor = that.properties.style[that.type].color; 40 | } 41 | 42 | that.meshes.push(GEOMETRIES.LINE({ x1: x1, y1: y1, z1:0, x2: x2, y2: y2, z2:0, thickness: thickness, color: lineColor})); 43 | 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/scene/cameras.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/cameras.js 4 | */ 5 | 6 | var CAMERAS = (function () { 7 | 8 | var _orbitDelta = 0; 9 | 10 | /** 11 | * Zoom support for orthogonal Camera 12 | */ 13 | _updateZoom = function(event){ 14 | 15 | var zoom = 0.02, 16 | newZoom = zoom, 17 | delta = 0; 18 | 19 | /** 20 | * Support for WebKit / Opera / Explorer 9 / Firefox 21 | */ 22 | delta = (event.wheelDelta)? (event.wheelDelta / 40): delta; 23 | delta = (event.detail)? (- event.detail / 3): delta; 24 | 25 | newZoom -= (delta * 0.001); 26 | 27 | this.left = - newZoom * (this.right / zoom); 28 | this.right = newZoom * (this.right / zoom); 29 | this.top = newZoom * (this.top / zoom); 30 | this.bottom = - newZoom * (this.top / zoom); 31 | } 32 | 33 | /** 34 | * Orbits camera around scene center in linear form 35 | */ 36 | _orbitAroundCenter = function(scene){ 37 | 38 | var date = new Date(); // for now 39 | date =date * 0.0001; 40 | 41 | // Update camera position 42 | this.position.x = Math.cos( date ) * 500; 43 | this.position.z = Math.sin( date ) * 500; 44 | 45 | // Orient camera to scene center 46 | this.lookAt( scene.position ); 47 | } 48 | 49 | return { 50 | DEFAULT: function(width, height){ 51 | var width = width || window.innerWidth, 52 | height = height || window.innerHeight, 53 | zoom = 0.5, 54 | zDepth = 100; 55 | 56 | var camera = new THREE.OrthographicCamera( zoom * -width, zoom * width, zoom * height, zoom * -height, -10000, 10000 ); 57 | camera.position.set(0, 0, zDepth); 58 | camera.updateZoom = _updateZoom; 59 | camera.orbitAroundCenter = _orbitAroundCenter; 60 | 61 | return camera; 62 | } 63 | }; 64 | })(); 65 | 66 | -------------------------------------------------------------------------------- /src/init.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: init.js 4 | */ 5 | 6 | var d3to3 = (function () { 7 | 8 | /** 9 | * Library Configuration 10 | */ 11 | 12 | var _d3 = {}; 13 | var _this = { 14 | loaded: false, 15 | about: { 16 | name: "d3to3", 17 | version: "0.0.1" 18 | } 19 | }; 20 | 21 | /** 22 | * Controller Instances 23 | */ 24 | 25 | _this.instances = {}; 26 | _this.currentInstance = undefined; 27 | 28 | /** 29 | * Intiializer 30 | */ 31 | 32 | _this.initializer = ({ 33 | init: function () { 34 | 35 | if (typeof d3 === 'undefined'){ 36 | LOGGER.report({'message': 'Failed to load D3.JS Library'}); 37 | return; 38 | } 39 | if (typeof THREE === 'undefined'){ 40 | LOGGER.report({'message': 'Failed to load Three.JS Library'}); 41 | return; 42 | } 43 | if (!(window.WebGLRenderingContext && (document.createElement("canvas").getContext("webgl")))){ 44 | LOGGER.report({'message': 'Your browser does not support WebGL/Canvas support.'}); 45 | return; 46 | } 47 | 48 | _d3 = Object.create(d3); 49 | _this.loaded = true; 50 | } 51 | }).init(); 52 | 53 | /** 54 | * Public API 55 | */ 56 | 57 | 58 | _this.updateData = function(properties){ 59 | _this.instances[properties['source']].updateMeshes(properties['data']); 60 | } 61 | 62 | _this.baseData = function(properties){ 63 | _this.instances[properties['source']].updateMeshes(properties['data']); 64 | } 65 | 66 | _this.render = function(properties){ 67 | if (Object.keys(_this.instances).length > 0 ){ 68 | if ( properties.hasOwnProperty('source') 69 | && _this.instances.hasOwnProperty(properties['source'])) { 70 | _this.instances[properties['source']].configure(properties) 71 | _this.instances[properties['source']].setup(); 72 | } 73 | } else { 74 | LOGGER.report({'message': 'Failed to render output. No SVG source was set!'}); 75 | } 76 | } 77 | 78 | if (_this.loaded) { 79 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | concat: { 7 | options: { 8 | separator: ';' 9 | }, 10 | dist: { 11 | src: [ 12 | 'src/init.js', 13 | 'src/setup.js', 14 | 'src/scene/materials.js', 15 | 'src/scene/geometries.js', 16 | 'src/scene/cameras.js', 17 | 'src/scene/renderers.js', 18 | 'src/scene/groups.js', 19 | 'src/scene/controls.js', 20 | 'src/views/base.js', 21 | 'src/views/line.js', 22 | 'src/views/axis.js', 23 | 'src/views/text.js', 24 | 'src/views/wireframe.js', 25 | 'src/views/circle.js', 26 | 'src/scene/lights.js', 27 | 'src/scene/parser.js', 28 | 'src/controller.js', 29 | 'src/utils/colors.js', 30 | 'src/utils/logger.js', 31 | 'src/utils/helpers.js', 32 | 'src/utils/units.js', 33 | 'src/teardown.js', 34 | 'src/dependencies/OrbitControls.js', 35 | 'src/dependencies/helvetiker_regular.typeface.js' 36 | ], 37 | dest: 'dist/<%= pkg.name %>.js' 38 | } 39 | }, 40 | uglify: { 41 | options: { 42 | compress: true, 43 | mangle: true, 44 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' 45 | }, 46 | build: { 47 | src: 'dist/<%= pkg.name %>.js', 48 | dest: 'dist/<%= pkg.name %>.min.js' 49 | } 50 | }, 51 | watch: { 52 | scripts: { 53 | files: [ 54 | 'src/*.js', 'src/**/*.js' 55 | ], 56 | tasks: [ 57 | 'concat', 'uglify' 58 | ], 59 | options: { 60 | livereload: true 61 | } 62 | } 63 | } 64 | }); 65 | 66 | // Grunt Plugins 67 | grunt.loadNpmTasks('grunt-contrib-uglify'); 68 | grunt.loadNpmTasks('grunt-contrib-concat'); 69 | grunt.loadNpmTasks('grunt-contrib-watch'); 70 | 71 | // Grunt Tasks 72 | grunt.registerTask('default', ['concat', 'uglify', 'watch']); 73 | }; 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # d3ToThree 2 | 3 | 4 | 5 | 6 | Transform two-dimension `D3.js` graphs to three-dimensional using `Three.js` 7 | 8 | ## Dependencies 9 | - [D3.js v3.5.5](https://d3js.org/) 10 | - [Three.js r70](https://threejs.org/) 11 | 12 | d3toThree diagram 13 | 14 | 15 | ## Examples 16 | 17 | [Network Graph](https://github.com/emiliosnic/d3toThree/blob/master/examples/network.html) 18 | 19 | Transforms 2D network graph to 3D 20 | network_graph 21 | 22 | 23 | [Scatter Plot](https://github.com/emiliosnic/d3toThree/blob/master/examples/scatter_plot.html) 24 | 25 | scatter_plot 26 | 27 | [Scatter Plot Animation](https://github.com/emiliosnic/d3toThree/blob/master/examples/scatter_plot_animation.html) 28 | 29 | scatter_plot_animation 30 | 31 | 32 | ## Performance 33 | 34 | FPS performance graph for datasets of 100 – 20,000 nodes. 35 | 36 | fps 37 | 38 | Initialization time graph for datasets of 100 – 20,000 nodes. 39 | 40 | initialization 41 | 42 | 43 | ## Versioning 44 | For the versions available, see the [releases for this repository](https://github.com/emiliosnic/d3toThree/releases) 45 | -------------------------------------------------------------------------------- /src/utils/units.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: utils/units.js 4 | */ 5 | 6 | var UNITS = (function () { 7 | 8 | return { 9 | extractThickness: function (input) { 10 | 11 | input = input.replace("stroke-width: ", ""); 12 | input = input.replace("px;", ""); 13 | 14 | var values = parseInt(input) || 1; 15 | 16 | return values; 17 | }, 18 | extractTranslation: function (input) { 19 | 20 | if (typeof input !== "string") 21 | return { x: 0, y: 0}; 22 | 23 | var translation = /\(([^)]+)\)/.exec(input)[1].split(','), 24 | offsetX = parseInt(translation[0]) || 0, 25 | offsetY = parseInt(translation[1]) || 0; 26 | 27 | return { 28 | x: offsetX, 29 | y: offsetY 30 | }; 31 | }, 32 | extractRotation: function (input) { 33 | if (typeof input !== "string") 34 | return 0; 35 | 36 | // Convert to clockwise 37 | 38 | var degrees = /\(([^)]+)\)/.exec(input)[1], 39 | degrees = (degrees<0)? (360 - Math.abs(degrees)): degrees; 40 | 41 | var radians = THREE.Math.degToRad(degrees); 42 | 43 | return radians; 44 | }, 45 | extractSVGPath: function(input) { 46 | 47 | var points = [], 48 | parsedInput = input.split(/(?=[MVHV])/); 49 | 50 | parsedInput.forEach(function(item, i){ 51 | 52 | var index = item.charAt(0), 53 | values = item.substring(1).split(','); 54 | 55 | if (index === "V"){ 56 | points.push({x: "V", y: values[0]}) 57 | 58 | } else if (index === "H"){ 59 | points.push({x: values[0], y: "H"}) 60 | 61 | } else { 62 | points.push({x: values[0], y: values[1]}) 63 | } 64 | }); 65 | 66 | // Normalize all points to numbers 67 | 68 | for (var j = 1; j < points.length; j++) { 69 | if (points[j].x == "V") { 70 | points[j].x = points[j-1].x; 71 | } 72 | if (points[j].y == "H") { 73 | points[j].y = points[j-1].y; 74 | } 75 | } 76 | return points; 77 | }, 78 | normalizeV: function(value, canvas) { 79 | 80 | var normalizedValue = (canvas.height/2 - value), 81 | normalizedValue = (value <= canvas.height)? normalizedValue: -normalizedValue; 82 | 83 | return (normalizedValue - canvas.offsetTop); 84 | }, 85 | 86 | normalizeH: function(value, canvas) { 87 | var normalizedValue = (canvas.width/2 - value), 88 | normalizedValue = (value <= canvas.width)? -normalizedValue: normalizedValue; 89 | 90 | return (normalizedValue + canvas.offsetLeft); 91 | } 92 | 93 | }; 94 | })(); 95 | -------------------------------------------------------------------------------- /src/utils/helpers.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: utils/helpers.js 4 | */ 5 | 6 | /** 7 | * Extract Node Protype 8 | */ 9 | 10 | Object.prototype.extractNode = function(key) { 11 | 12 | var obj = this; 13 | 14 | if (key in this){ 15 | obj = this[key]; 16 | } else { 17 | for (var item in this) { 18 | if (this.hasOwnProperty(item) && this[item].nodeName === key){ 19 | obj = this[item]; 20 | break; 21 | } 22 | } 23 | } 24 | return obj; 25 | }; 26 | 27 | /** 28 | * Extension Helper 29 | */ 30 | 31 | function extend (base, extension) { 32 | if (arguments.length > 2) 33 | [].forEach.call(arguments, function (extension) { 34 | extend(base, extension) 35 | }) 36 | else 37 | for (var k in extension) 38 | base[k] = extension[k] 39 | return base; 40 | } 41 | 42 | 43 | /** 44 | * Observer Factory 45 | */ 46 | 47 | function ObserverFactory(){} 48 | 49 | ObserverFactory.queue = []; 50 | var observerFactory = new ObserverFactory 51 | 52 | ObserverFactory.prototype.observe = function() { 53 | [].forEach.call(arguments, function (obj) { 54 | if (obj) 55 | ObserverFactory.queue.push(obj); 56 | }); 57 | return this; 58 | }; 59 | 60 | ObserverFactory.prototype.then = function(callback) { 61 | this.callback = callback || {}; 62 | return this; 63 | }; 64 | 65 | ObserverFactory.prototype.expectKeyType = function(keyType) { 66 | this.expectedType = keyType; 67 | return this; 68 | }; 69 | 70 | ObserverFactory.prototype.expectKey = function(key) { 71 | this.expectedKey = key; 72 | return this; 73 | }; 74 | 75 | ObserverFactory.prototype.type = function(type){ 76 | var constr = type; 77 | 78 | if (typeof ObserverFactory[constr] !== "function"){ 79 | LOGGER.report({'message': ('Failed to create Observer Factory instance - Caller '+arguments.callee.caller.name)}); 80 | } 81 | if (typeof ObserverFactory[constr].prototype.drive !== "function") { 82 | ObserverFactory[constr].prototype = new ObserverFactory(); 83 | } 84 | return new ObserverFactory[constr](); 85 | } 86 | 87 | ObserverFactory.attr = function() { this.type = 'attr'; } 88 | ObserverFactory.append = function() { this.type = 'append'; } 89 | 90 | ObserverFactory.prototype.notify = function(args) { 91 | 92 | var key = args.key || {}, 93 | keyType = args.keyType || {}, 94 | value = args.value || {}, 95 | type = args.type || {}; 96 | 97 | if (!ObserverFactory.hasOwnProperty(type)) 98 | return; 99 | 100 | ObserverFactory.queue.some(function(observer, i) { 101 | 102 | if (observer.type == type && 103 | (observer.expectedKey == key) || (observer.expectedType == keyType)){ 104 | 105 | if (typeof observer.callback === "function" && value != null){ 106 | observer.callback(value); 107 | } 108 | ObserverFactory.queue.splice(i, 1); 109 | return true; 110 | } 111 | }); 112 | } 113 | 114 | -------------------------------------------------------------------------------- /src/scene/geometries.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/geometries.js 4 | */ 5 | 6 | var GEOMETRIES = (function () { 7 | 8 | /** 9 | * Restore object color and opacity 10 | */ 11 | 12 | _show = function(){ 13 | this.material.color.set(this.savedColor); 14 | this.material.opacity = 1; 15 | this.material.transparent = true; 16 | this.verticesNeedUpdate = true; 17 | } 18 | 19 | /** 20 | * Hide object (by setting low opacity) 21 | */ 22 | 23 | _hide = function(){ 24 | this.material.opacity = 0.1; 25 | this.material.transparent = true; 26 | } 27 | 28 | return { 29 | CIRCLE: function (properties) { 30 | var circle = new THREE.Mesh(new THREE.CircleGeometry(properties.radius, 64), MATERIALS.DEFAULT_2D(properties.color)); 31 | circle.position.set(properties.x, properties.y, properties.z); 32 | circle.show = _show; 33 | circle.hide = _hide; 34 | circle.savedColor = COLORS.normalize(properties.color); 35 | 36 | return circle; 37 | }, 38 | SPHERE: function (properties) { 39 | var sphere = new THREE.Mesh(new THREE.SphereGeometry(properties.radius, 64, 64), MATERIALS.DEFAULT_3D(properties.color)); 40 | sphere.position.set(properties.x, properties.y, properties.z); 41 | sphere.show = _show; 42 | sphere.hide = _hide; 43 | sphere.savedColor = COLORS.normalize(properties.color); 44 | 45 | return sphere; 46 | }, 47 | TEXT: function (properties) { 48 | 49 | var WIDTH = 8, 50 | HEIGHT = 0; 51 | 52 | var textGeom = new THREE.TextGeometry( properties.text, { 53 | size: WIDTH, 54 | height: HEIGHT 55 | }); 56 | var textMesh = new THREE.Mesh( textGeom, MATERIALS.DEFAULT_2D(properties.color)); 57 | textMesh.position.set( 58 | properties.x - WIDTH/2, 59 | properties.y - WIDTH/2, 60 | properties.z ); 61 | 62 | // Disable hide and show controls for text sprites 63 | textMesh.show = function(){}; 64 | textMesh.hide = function(){}; 65 | 66 | return textMesh; 67 | }, 68 | LINE: function (properties) { 69 | 70 | var material = properties.material || MATERIALS.LINE(properties.color, properties.thickness); 71 | 72 | var geometry = new THREE.Geometry(); 73 | geometry.vertices.push(new THREE.Vector3(properties.x1, properties.y1, properties.z1)); 74 | geometry.vertices.push(new THREE.Vector3(properties.x2, properties.y2, properties.z2)); 75 | 76 | var line = new THREE.Line(geometry, material); 77 | line.show = _show; 78 | line.hide = _hide; 79 | line.savedColor = COLORS.normalize(properties.color); 80 | 81 | return line; 82 | }, 83 | AXIS: function (properties) { 84 | 85 | var material = properties.material || MATERIALS.AXIS(); 86 | 87 | var geometry = new THREE.Geometry(); 88 | geometry.vertices.push(new THREE.Vector3(properties.x1, properties.y1, properties.z1)); 89 | geometry.vertices.push(new THREE.Vector3(properties.x2, properties.y2, properties.z2)); 90 | 91 | var axis = new THREE.Line(geometry, material); 92 | 93 | // Disable hide and show controls for axis 94 | axis.show = function(){}; 95 | axis.hide = function(){}; 96 | 97 | return axis; 98 | } 99 | } 100 | 101 | })(); 102 | -------------------------------------------------------------------------------- /src/views/axis.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: views/axis.js 4 | */ 5 | 6 | VIEW.axis = function() { 7 | 8 | this.type = 'axis'; 9 | this.meshes = []; 10 | 11 | this.load = function(axis){ 12 | 13 | var data = axis.data, 14 | transform = UNITS.extractTranslation(axis.transform); 15 | 16 | for (index = 0; index < data.length; index++){ 17 | 18 | /** 19 | * Extract Axis Points 20 | */ 21 | 22 | if (data[index].nodeName === "g") { 23 | 24 | /** 25 | * Extract Ticks 26 | */ 27 | 28 | var tickPosition = UNITS.extractTranslation(data[index].attributes.extractNode('transform').nodeValue), 29 | tickLine = { 30 | x: parseInt(data[index].childNodes.extractNode('line').attributes.extractNode('x2').nodeValue), 31 | y: parseInt(data[index].childNodes.extractNode('line').attributes.extractNode('y2').nodeValue) 32 | }; 33 | 34 | var startX = UNITS.normalizeH(tickPosition.x + transform.x, this.properties.canvas), 35 | startY = UNITS.normalizeV(tickPosition.y + transform.y, this.properties.canvas), 36 | endX = startX + tickLine.x, 37 | endY = startY - tickLine.y; 38 | 39 | /** 40 | * Project to Z if this is a depth axis 41 | */ 42 | 43 | if (axis && axis['depthAxis']){ 44 | 45 | // Rotate 90 degrees 46 | 47 | } 48 | 49 | this.meshes.push( 50 | GEOMETRIES.AXIS({ 51 | 'x1': startX, 'y1': startY, 'z1':0, 52 | 'x2': endX , 'y2': endY , 'z2':0 53 | }) 54 | ); 55 | 56 | /** 57 | * Extract Text 58 | */ 59 | var text = data[index].childNodes.extractNode('text'), 60 | textData = text.textContent, 61 | textSize = parseFloat(text.attributes.extractNode('dy').nodeValue), 62 | textOffsets = { 63 | x: parseInt(text.attributes.extractNode('x').nodeValue), 64 | y: parseInt(text.attributes.extractNode('y').nodeValue) 65 | }; 66 | 67 | this.meshes.push( 68 | GEOMETRIES.TEXT({ 69 | text: textData, 70 | x: (startX + textOffsets.x + tickLine.x), 71 | y: (startY - textOffsets.y - tickLine.y), 72 | z: 0 73 | }) 74 | ); 75 | 76 | 77 | } else if (data[index].nodeName === "path") { 78 | 79 | /** 80 | * Extract Axis Paths 81 | */ 82 | 83 | var points = UNITS.extractSVGPath(data[index].attributes.extractNode('d').nodeValue); 84 | 85 | for (var j = 1; j < points.length; j++) { 86 | 87 | var startY = UNITS.normalizeV(parseInt(points[j-1].y), this.properties.canvas) - transform.y; 88 | startX = UNITS.normalizeH(parseInt(points[j-1].x), this.properties.canvas) + transform.x; 89 | endX = UNITS.normalizeH(parseInt(points[j].x), this.properties.canvas ) + transform.x; 90 | endY = UNITS.normalizeV(parseInt(points[j].y), this.properties.canvas ) - transform.y; 91 | 92 | /** 93 | * Project to Z if this is a depth axis 94 | */ 95 | 96 | if (axis && axis['depthAxis']){ 97 | 98 | // Rotate 90 degrees 99 | var test = GEOMETRIES.AXIS({ 100 | x1: startX, y1: startY, z1:0, 101 | x2: endX, y2:endY , z2:0 102 | }); 103 | } 104 | 105 | this.meshes.push( 106 | GEOMETRIES.AXIS({ 107 | x1: startX, y1: startY, z1:0, 108 | x2: endX, y2:endY , z2:0 109 | }) 110 | ) 111 | } 112 | } 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /examples/network.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | D3to3 - Examples - Network 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 29 | 30 | 31 | 32 | 33 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /src/scene/groups.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: scene/groups.js 4 | */ 5 | 6 | 7 | var GROUPS = (function () { 8 | 9 | 10 | /** 11 | * Find all intersecting lines in a sphere and return an array with the corresponding group-indices of these lines meshes 12 | */ 13 | 14 | _findIntersectingLines = function(properties){ 15 | 16 | var intersectingObjects = []; 17 | 18 | properties.group.children.forEach(function(line, lineIndex){ 19 | 20 | // Find All intersecting Lines 21 | if (line.type == "Line"){ 22 | for (var vertexIndex = 0; vertexIndex <=1; vertexIndex++) { 23 | 24 | var xDiff = (Math.abs(line.geometry.vertices[vertexIndex].x) - Math.abs(properties.baseObject.position.x)), 25 | yDiff = (Math.abs(line.geometry.vertices[vertexIndex].y) - Math.abs(properties.baseObject.position.y)), 26 | zDiff = (Math.abs(line.geometry.vertices[vertexIndex].z) - Math.abs(properties.baseObject.position.z)); 27 | 28 | if (Math.abs(xDiff + yDiff + zDiff) < 0.1){ 29 | intersectingObjects.push({ 30 | 'lineIndex':lineIndex, 31 | 'vertexIndex':vertexIndex 32 | }); 33 | } 34 | } 35 | } 36 | }); 37 | 38 | return intersectingObjects; 39 | } 40 | 41 | /** 42 | * Determine z offsets for group's meshes for network graphs 43 | */ 44 | 45 | _expandNetworkDepth = function(type){ 46 | switch (type){ 47 | case 'degree-centrality' : _expandUsingDegreeCentrality(this); break; 48 | default : _expandUsingDegreeCentrality(this); 49 | } 50 | } 51 | 52 | /** 53 | * Expand graph using degree centrality 54 | */ 55 | 56 | _expandUsingDegreeCentrality = function(group){ 57 | 58 | var nodeGroups = [], 59 | that = group; 60 | 61 | group.children.forEach(function(circle, circleIndex){ 62 | if (circle.type == "Mesh" && circle.geometry.type == "SphereGeometry"){ 63 | var groupConnectedLinesIndices = _findIntersectingLines({ 64 | 'group' : that, 65 | 'baseObject' : circle 66 | }); 67 | nodeGroups.push({ 68 | 'circleIndex': circleIndex, 69 | 'lineIndices': groupConnectedLinesIndices 70 | }) 71 | } 72 | }); 73 | 74 | var maxDepth = 0, 75 | zDepth = 0; 76 | 77 | nodeGroups.forEach(function(nodeGroup){ 78 | 79 | if (nodeGroup.lineIndices.length > 0) { 80 | zDepth = 5 * (nodeGroup.lineIndices.length); 81 | if (zDepth >= maxDepth){ 82 | maxDepth = zDepth 83 | } 84 | } 85 | 86 | // Update node depth 87 | group.children[nodeGroup.circleIndex].position.setZ(zDepth); 88 | 89 | // Update line depths 90 | nodeGroup.lineIndices.forEach(function(line){ 91 | that.children[line.lineIndex].geometry.vertices[line.vertexIndex].z = zDepth; 92 | that.children[line.lineIndex].geometry.verticesNeedUpdate = true; 93 | }); 94 | 95 | // Update group's depth 96 | group.position.setZ(-maxDepth/2); 97 | }) 98 | } 99 | 100 | /** 101 | * Call hide on connected nodes for network groups 102 | */ 103 | 104 | _highlightConnectedNodes = function(origin){ 105 | 106 | var that = this; 107 | 108 | this.children.forEach(function(line){ 109 | if (line.type == "Line"){ 110 | for (var verticeIndex = 0; verticeIndex <=1; verticeIndex++) { 111 | 112 | var xDiff = (Math.abs(line.geometry.vertices[verticeIndex].x) - Math.abs(origin.position.x)), 113 | yDiff = (Math.abs(line.geometry.vertices[verticeIndex].y) - Math.abs(origin.position.y)), 114 | zDiff = (Math.abs(line.geometry.vertices[verticeIndex].z) - Math.abs(origin.position.z)); 115 | 116 | if (Math.abs(xDiff + yDiff + zDiff) < 0.1){ 117 | 118 | // Unhide Line 119 | line.show(); 120 | 121 | // Update end nodes with colors 122 | that.children.forEach(function(node){ 123 | if (node.type == "Mesh" && node != origin){ 124 | for (var verticeIndex = 0; verticeIndex <=1; verticeIndex++) { 125 | 126 | var xDiff2 = (Math.abs(line.geometry.vertices[verticeIndex].x) - Math.abs(node.position.x)), 127 | yDiff2 = (Math.abs(line.geometry.vertices[verticeIndex].y) - Math.abs(node.position.y)), 128 | zDiff2 = (Math.abs(line.geometry.vertices[verticeIndex].z) - Math.abs(node.position.z)); 129 | 130 | if (Math.abs(xDiff2 + yDiff2 + zDiff2) < 0.1){ 131 | node.show(); 132 | line.material.color.set(node.material.color); 133 | line.verticesNeedUpdate = true; 134 | } 135 | } 136 | } 137 | }) 138 | } 139 | } 140 | } 141 | }) 142 | } 143 | 144 | return { 145 | DEFAULT: function () { 146 | var group = new THREE.Group(); 147 | group.expandNetworkDepth = _expandNetworkDepth; 148 | group.highlightConnectedNodes = _highlightConnectedNodes; 149 | 150 | 151 | return group; 152 | } 153 | }; 154 | })(); 155 | 156 | -------------------------------------------------------------------------------- /examples/scatter_plot.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | D3to3 - Examples - Scatter Plot 8 | 9 | 10 | 11 | 12 | 42 | 43 | 44 | 45 | 46 | 56 | 57 | 58 | 59 | 60 | 61 | 246 | 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /src/setup.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: setup.js 4 | */ 5 | 6 | // Extend D3 7 | 8 | extend(d3.selection.prototype, { 9 | 10 | d3to3: function() { 11 | this.axis = function(properties){ 12 | 13 | var depthAxis = false; 14 | if (properties && properties['depthAxis']){ 15 | depthAxis = properties['depthAxis']; 16 | } 17 | 18 | _this.instances[_this.currentInstance].model.axes.push({ 19 | 'data' : this[0].extractNode('g').childNodes, 20 | 'depthAxis': depthAxis, 21 | 'transform' : this[0].extractNode('g').attributes.extractNode('transform').nodeValue 22 | }) 23 | 24 | return this; 25 | } 26 | this.data = function(){ 27 | _this.instances[_this.currentInstance].model.content.push({ 28 | 'data' : this[0], 29 | 'type' : this[0][0].nodeName 30 | }) 31 | return this; 32 | } 33 | 34 | this.text = function(){ 35 | var sprite = this[0].extractNode('text'); 36 | _this.instances[_this.currentInstance].model.texts.push({ 37 | 'x' : (sprite.attributes.extractNode('x').nodeValue) || 0, 38 | 'y' : (sprite.attributes.extractNode('y').nodeValue) || 0, 39 | 'val' : sprite.textContent, 40 | 'transform' : sprite.attributes.extractNode('transform').nodeValue, 41 | 'length' : sprite.textLength.baseVal.value, 42 | 'type' : this[0][0].nodeName 43 | }) 44 | 45 | return this; 46 | } 47 | return this; 48 | } 49 | }); 50 | 51 | 52 | // Setup D3 Hooks 53 | 54 | _this.setupHooks = ({ 55 | setup: function () { 56 | 57 | var hook_selectAll = _d3.selection.prototype.selectAll, 58 | hook_select = _d3.selection.prototype.select, 59 | hook_data = _d3.selection.prototype.data, 60 | hook_attr = _d3.selection.prototype.attr; 61 | hook_classed = _d3.selection.prototype.classed, 62 | hook_style = _d3.selection.prototype.style, 63 | hook_property = _d3.selection.prototype.property, 64 | hook_text = _d3.selection.prototype.text, 65 | hook_html = _d3.selection.prototype.html, 66 | hook_append = _d3.selection.prototype.append, 67 | hook_insert = _d3.selection.prototype.insert, 68 | hook_remove = _d3.selection.prototype.remove, 69 | hook_datum = _d3.selection.prototype.datum, 70 | hook_filter = _d3.selection.prototype.filter, 71 | hook_order = _d3.selection.prototype.order, 72 | hook_sort = _d3.selection.prototype.sort, 73 | hook_each = _d3.selection.prototype.each, 74 | hook_call = _d3.selection.prototype.call, 75 | hook_empty = _d3.selection.prototype.empty, 76 | hook_node = _d3.selection.prototype.node, 77 | hook_size = _d3.selection.prototype.size, 78 | hook_enter_append = _d3.selection.enter.prototype.append, 79 | hook_enter_empty = _d3.selection.enter.prototype.empty, 80 | hook_enter_node = _d3.selection.enter.prototype.node, 81 | hook_enter_call = _d3.selection.enter.prototype.call, 82 | hook_enter_select = _d3.selection.enter.prototype.select, 83 | hook_enter_insert = _d3.selection.enter.prototype.insert, 84 | hook_enter_size = _d3.selection.enter.prototype.size; 85 | 86 | _d3.selection.enter.prototype.empty = function() { return hook_enter_empty.apply(this, arguments); } 87 | _d3.selection.enter.prototype.node = function() { return hook_enter_node.apply(this, arguments); } 88 | _d3.selection.enter.prototype.call = function() { return hook_enter_call.apply(this, arguments); } 89 | _d3.selection.enter.prototype.select = function() { return hook_enter_select.apply(this, arguments); } 90 | _d3.selection.enter.prototype.insert = function() { return hook_enter_insert.apply(this, arguments); } 91 | _d3.selection.enter.prototype.size = function() { return hook_enter_size.apply(this, arguments); } 92 | _d3.selection.enter.prototype.append = function() { return hook_append.apply(this, arguments); } 93 | _d3.selection.prototype.selectAll = function() { return hook_selectAll.apply(this, arguments); } 94 | _d3.selection.prototype.select = function() { return hook_select.apply(this, arguments); } 95 | _d3.selection.prototype.classed = function() { return hook_classed.apply(this, arguments); } 96 | _d3.selection.prototype.style = function() { return hook_style.apply(this, arguments); } 97 | _d3.selection.prototype.property = function() { return hook_property.apply(this, arguments); } 98 | _d3.selection.prototype.text = function() { return hook_text.apply(this, arguments); } 99 | _d3.selection.prototype.html = function() { return hook_html.apply(this, arguments); } 100 | _d3.selection.prototype.insert = function() { return hook_insert.apply(this, arguments); } 101 | _d3.selection.prototype.remove = function() { return hook_remove.apply(this, arguments); } 102 | _d3.selection.prototype.datum = function() { return hook_datum.apply(this, arguments); } 103 | _d3.selection.prototype.filter = function() { return hook_filter.apply(this, arguments); } 104 | _d3.selection.prototype.order = function() { return hook_order.apply(this, arguments); } 105 | _d3.selection.prototype.sort = function() { return hook_sort.apply(this, arguments); } 106 | _d3.selection.prototype.empty = function() { return hook_empty.apply(this, arguments); } 107 | _d3.selection.prototype.node = function() { return hook_node.apply(this, arguments); } 108 | _d3.selection.prototype.size = function() { return hook_size.apply(this, arguments); } 109 | _d3.selection.prototype.data = function() { return hook_data.apply(this, arguments); } 110 | _d3.selection.prototype.call = function() { return hook_call.apply(this, arguments); } 111 | _d3.selection.prototype.each = function() { return hook_each.apply(this, arguments); } 112 | 113 | _d3.selection.prototype.attr = function() { 114 | /** 115 | * Notify attr observers 116 | */ 117 | observerFactory.notify({'type':'attr', 'key':arguments[0], 'value':arguments[1]}); 118 | 119 | return hook_attr.apply(this, arguments); 120 | } 121 | _d3.selection.prototype.append = function(){ 122 | observerFactory.notify({'type':'append', 'key':arguments[0], 'value':arguments[1]}); 123 | 124 | /** 125 | * Determine SVG width, height and offsets 126 | */ 127 | 128 | if (arguments[0] === 'svg'){ 129 | var svgID = this[0][0].id; 130 | 131 | /** 132 | * Setup a new library instance for every SVG element 133 | */ 134 | _this.instances[svgID] = new Controller(); 135 | _this.currentInstance = svgID; 136 | 137 | /** 138 | * Setup observer factories to determine width and height 139 | */ 140 | observerFactory.observe( 141 | observerFactory.type('attr').expectKey('width').then(function(value){ 142 | _this.instances[svgID].canvas.width = value; 143 | }), 144 | observerFactory.type('attr').expectKey('height').then(function(value){ 145 | _this.instances[svgID].canvas.height = value; 146 | }), 147 | observerFactory.type('append').expectKey('g').then(function(value){}), 148 | observerFactory.type('attr').expectKey('transform').then(function(value){ 149 | var offsets = UNITS.extractTranslation(value); 150 | _this.instances[svgID].canvas.offsetLeft = offsets.x; 151 | _this.instances[svgID].canvas.offsetTop = offsets.y; 152 | }) 153 | ); 154 | } 155 | return hook_append.apply(this, arguments); 156 | } 157 | } 158 | }).setup(); 159 | -------------------------------------------------------------------------------- /examples/scatter_plot_animation.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | D3to3 - Examples - Scatter Plot Animation 8 | 9 | 10 | 11 | 12 | 34 | 35 | 36 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /src/controller.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * File: controller.js 4 | */ 5 | 6 | function Controller() { 7 | 8 | var _controller = {}; 9 | 10 | /** 11 | * Initialize Controller 12 | */ 13 | 14 | _controller.initializer = ({ 15 | init: function () { 16 | _controller.config = { 17 | 'source' : undefined, 18 | 'target' : undefined, 19 | 'controls' : false, 20 | '3D' : false, 21 | 'orbit' : false 22 | }; 23 | _controller.canvas = { 24 | offsetLeft : 0, 25 | offsetTop : 0, 26 | width : null, 27 | height : null 28 | } 29 | _controller.model = { 30 | axes : [], 31 | texts : [], 32 | content : [] 33 | }; 34 | } 35 | }).init(); 36 | 37 | 38 | /** 39 | * Create protected canvas objects 40 | */ 41 | 42 | var camera, renderer, scene, group, container, controls, canvas, light, mouse, raycaster, 43 | ENABLE_ANIMATION = true; 44 | 45 | /** 46 | * Setup WebGL Canvas 47 | */ 48 | 49 | var setupCanvas = function () { 50 | 51 | camera = CAMERAS.DEFAULT(_controller.canvas.width, _controller.canvas.height); 52 | light = LIGHTS.DEFAULT(); 53 | renderer = RENDERERS.DEFAULT(_controller.canvas.width, _controller.canvas.height); 54 | group = GROUPS.DEFAULT(); 55 | mouse = new THREE.Vector3(); 56 | raycaster = new THREE.Raycaster(); 57 | 58 | 59 | if (_controller.config.controls){ 60 | controls = CONTROLS.Orbit(camera); 61 | controls.addEventListener( 'change', function(){ 62 | ENABLE_ANIMATION = false; 63 | camera.updateProjectionMatrix(); 64 | light.alignToPosition(camera.position); 65 | render(); 66 | }); 67 | renderer.domElement.addEventListener( 'mousewheel', mousewheel, false ); 68 | renderer.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); 69 | renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false ); 70 | } 71 | 72 | if (_controller.config.target != undefined){ 73 | container = document.getElementById(_controller.config.target); 74 | } else { 75 | container = document.getElementById(_controller.config.source); 76 | } 77 | container.appendChild( renderer.domElement ); 78 | }; 79 | 80 | /** 81 | * Setup Views 82 | */ 83 | 84 | var setupViews = function () { 85 | 86 | // Setup Data Views 87 | _controller.model.content.forEach(function(model){ 88 | new VIEW() 89 | .type(model.type) 90 | .setProperties({ 91 | 'canvas': _controller.canvas, 92 | '3D' : _controller.config['3D'], 93 | 'style' : _controller.config.style 94 | }) 95 | .loadData(model.data) 96 | .appendTo(group); 97 | }); 98 | 99 | // Setup Axes Views 100 | _controller.model.axes.forEach(function(axis){ 101 | new VIEW() 102 | .type('axis') 103 | .setProperties({ 104 | 'canvas':_controller.canvas, 105 | '3D': _controller.config['3D'] 106 | }) 107 | .loadData(axis) 108 | .appendTo(group); 109 | }) 110 | 111 | 112 | 113 | // Setup Text Views 114 | _controller.model.texts.forEach(function(text){ 115 | new VIEW() 116 | .type(text.type) 117 | .setProperties({ 118 | 'canvas':_controller.canvas, 119 | '3D': _controller.config['3D'] 120 | }) 121 | .loadData(text) 122 | .appendTo(group); 123 | }) 124 | 125 | // Flush Model 126 | _controller.model.content = []; 127 | 128 | // Flush the SVG tree (If source and targer are the same) 129 | 130 | if (_controller.config.source == _controller.config.target || _controller.config.target == undefined){ 131 | document.getElementById(_controller.config.source).getElementsByTagName('svg')[0].remove(); 132 | } 133 | 134 | // Process network graph (if any) 135 | 136 | if ( _controller.config.network 137 | && _controller.config.network['zDepth'] 138 | && _controller.config['3D']){ 139 | 140 | group.expandNetworkDepth(_controller.config.network['zDepth']); 141 | } 142 | 143 | // Populate scene 144 | 145 | scene = (new THREE.Scene()) 146 | .add(camera) 147 | .add(light) 148 | .add(group); 149 | } 150 | 151 | /** 152 | * Animate helper 153 | */ 154 | 155 | var animate = function () { 156 | render(); 157 | requestAnimationFrame(animate); 158 | } 159 | 160 | /** 161 | * Render helper 162 | */ 163 | 164 | var render = function() { 165 | 166 | 167 | if (ENABLE_ANIMATION && _controller.config.orbit ){ 168 | camera.orbitAroundCenter(scene); 169 | light.alignToPosition(camera.position); 170 | } 171 | camera.updateProjectionMatrix(); 172 | 173 | renderer.render( scene, camera ); 174 | } 175 | 176 | /** 177 | * Window resize helper 178 | */ 179 | 180 | function onWindowResize() { 181 | 182 | camera.aspect = window.innerWidth / window.innerHeight; 183 | camera.updateProjectionMatrix(); 184 | renderer.setSize( window.innerWidth, window.innerHeight ); 185 | render(); 186 | } 187 | 188 | /** 189 | * Mouse Wheel helper (for orthogonal camera) 190 | */ 191 | 192 | var mousewheel = function(event) { 193 | 194 | event.preventDefault(); 195 | event.stopPropagation(); 196 | 197 | camera.updateZoom(event); 198 | camera.updateProjectionMatrix(); 199 | 200 | renderer.render(scene,camera); 201 | } 202 | 203 | /** 204 | * Mouse Move processing (for network and 3D mode) 205 | */ 206 | 207 | function onDocumentMouseMove( event ) { 208 | 209 | event.preventDefault(); 210 | 211 | if (!_controller.config.network || !_controller.config['3D']) 212 | return; 213 | 214 | var xPerc = (UNITS.normalizeH(event.offsetX-_controller.canvas.offsetLeft,_controller.canvas)/renderer.domElement.width * 4 ), 215 | yPerc = (UNITS.normalizeV(event.offsetY-_controller.canvas.offsetTop, _controller.canvas)/renderer.domElement.height * 4 ); 216 | 217 | mouse.set( xPerc, yPerc, - 1); 218 | mouse.unproject( camera ); 219 | 220 | var dir = new THREE.Vector3(); 221 | dir.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); 222 | 223 | raycaster.set(mouse,dir); 224 | 225 | var intersects = raycaster.intersectObjects( group.children, true ); 226 | 227 | if (intersects.length>0){ 228 | // De-highlight all meshes in group 229 | group.children.forEach(function(object){ 230 | object.hide(); 231 | }) 232 | 233 | // Highlight intersected objects 234 | intersects.forEach(function(intersection){ 235 | intersection.object.show(); 236 | 237 | // If this is a network graph then also highlight connected nodes 238 | if (_controller.config.network){ 239 | group.highlightConnectedNodes(intersection.object); 240 | } 241 | 242 | }) 243 | } else { 244 | // De-highlight all meshes in group 245 | group.children.forEach(function(object){ 246 | object.show(); 247 | }) 248 | } 249 | } 250 | 251 | /** 252 | * Public Methods 253 | */ 254 | 255 | _controller.addedMeshes = false; 256 | 257 | _controller.updateMeshes = function(data){ 258 | 259 | if (!_controller.addedMeshes){ 260 | _controller.model.content.push({ 261 | 'data' : data[0], 262 | 'type' : data[0][0].nodeName 263 | }); 264 | _controller.addedMeshes = true; 265 | } else { 266 | 267 | var dataIndex = 0; 268 | 269 | if (! group instanceof THREE.Group) 270 | return; 271 | 272 | group.children.forEach(function(mesh, meshIndex){ 273 | if (mesh.geometry.type == "CircleGeometry" || mesh.geometry.type == "SphereGeometry"){ 274 | 275 | var baseX = data[0][dataIndex].cx.baseVal.value; 276 | var baseY = data[0][dataIndex].cy.baseVal.value; 277 | var baseRadius = data[0][dataIndex].r.baseVal.value; 278 | var scaleR = baseRadius / mesh.geometry.boundingSphere.radius; 279 | 280 | var x = UNITS.normalizeH(baseX, _controller.canvas), 281 | y = UNITS.normalizeV(baseY, _controller.canvas); 282 | 283 | 284 | mesh.scale.x = scaleR; 285 | mesh.scale.y = scaleR; 286 | mesh.scale.z = scaleR; 287 | 288 | mesh.position.setX(x); 289 | mesh.position.setX(x); 290 | mesh.position.setY(y); 291 | 292 | dataIndex++; 293 | 294 | } 295 | }) 296 | } 297 | } 298 | 299 | _controller.setup = function(){ 300 | 301 | setupCanvas(); 302 | setupViews(); 303 | animate(); 304 | } 305 | 306 | _controller.configure = function(properties){ 307 | try { 308 | for (property in properties){ 309 | _controller.config[property] = properties[property]; 310 | } 311 | } catch (err){ 312 | LOGGER.report({'message': 'Configuration failed.', 'error':err }); 313 | } 314 | } 315 | 316 | /** 317 | * Return instance reference 318 | */ 319 | 320 | return _controller ; 321 | } 322 | 323 | 324 | -------------------------------------------------------------------------------- /src/dependencies/OrbitControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author qiao / https://github.com/qiao 3 | * @author mrdoob / http://mrdoob.com 4 | * @author alteredq / http://alteredqualia.com/ 5 | * @author WestLangley / http://github.com/WestLangley 6 | * @author erich666 / http://erichaines.com 7 | */ 8 | /*global THREE, console */ 9 | 10 | // This set of controls performs orbiting, dollying (zooming), and panning. It maintains 11 | // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is 12 | // supported. 13 | // 14 | // Orbit - left mouse / touch: one finger move 15 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish 16 | // Pan - right mouse, or arrow keys / touch: three finter swipe 17 | 18 | THREE.OrbitControls = function ( object, domElement ) { 19 | 20 | this.object = object; 21 | this.domElement = ( domElement !== undefined ) ? domElement : document; 22 | 23 | // API 24 | 25 | // Set to false to disable this control 26 | this.enabled = true; 27 | 28 | // "target" sets the location of focus, where the control orbits around 29 | // and where it pans with respect to. 30 | this.target = new THREE.Vector3(); 31 | 32 | // center is old, deprecated; use "target" instead 33 | this.center = this.target; 34 | 35 | // This option actually enables dollying in and out; left as "zoom" for 36 | // backwards compatibility 37 | this.noZoom = false; 38 | this.zoomSpeed = 1.0; 39 | 40 | // Limits to how far you can dolly in and out ( PerspectiveCamera only ) 41 | this.minDistance = 0; 42 | this.maxDistance = Infinity; 43 | 44 | // Limits to how far you can zoom in and out ( OrthographicCamera only ) 45 | this.minZoom = 0; 46 | this.maxZoom = Infinity; 47 | 48 | // Set to true to disable this control 49 | this.noRotate = false; 50 | this.rotateSpeed = 1.0; 51 | 52 | // Set to true to disable this control 53 | this.noPan = false; 54 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push 55 | 56 | // Set to true to automatically rotate around the target 57 | this.autoRotate = false; 58 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 59 | 60 | // How far you can orbit vertically, upper and lower limits. 61 | // Range is 0 to Math.PI radians. 62 | this.minPolarAngle = 0; // radians 63 | this.maxPolarAngle = Math.PI; // radians 64 | 65 | // How far you can orbit horizontally, upper and lower limits. 66 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. 67 | this.minAzimuthAngle = - Infinity; // radians 68 | this.maxAzimuthAngle = Infinity; // radians 69 | 70 | // Set to true to disable use of the keys 71 | this.noKeys = false; 72 | 73 | // The four arrow keys 74 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 75 | 76 | // Mouse buttons 77 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT }; 78 | 79 | //////////// 80 | // internals 81 | 82 | var scope = this; 83 | 84 | var EPS = 0.000001; 85 | 86 | var rotateStart = new THREE.Vector2(); 87 | var rotateEnd = new THREE.Vector2(); 88 | var rotateDelta = new THREE.Vector2(); 89 | 90 | var panStart = new THREE.Vector2(); 91 | var panEnd = new THREE.Vector2(); 92 | var panDelta = new THREE.Vector2(); 93 | var panOffset = new THREE.Vector3(); 94 | 95 | var offset = new THREE.Vector3(); 96 | 97 | var dollyStart = new THREE.Vector2(); 98 | var dollyEnd = new THREE.Vector2(); 99 | var dollyDelta = new THREE.Vector2(); 100 | 101 | var theta; 102 | var phi; 103 | var phiDelta = 0; 104 | var thetaDelta = 0; 105 | var scale = 1; 106 | var pan = new THREE.Vector3(); 107 | 108 | var lastPosition = new THREE.Vector3(); 109 | var lastQuaternion = new THREE.Quaternion(); 110 | 111 | var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; 112 | 113 | var state = STATE.NONE; 114 | 115 | // for reset 116 | 117 | this.target0 = this.target.clone(); 118 | this.position0 = this.object.position.clone(); 119 | this.zoom0 = this.object.zoom; 120 | 121 | // so camera.up is the orbit axis 122 | 123 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); 124 | var quatInverse = quat.clone().inverse(); 125 | 126 | // events 127 | 128 | var changeEvent = { type: 'change' }; 129 | var startEvent = { type: 'start' }; 130 | var endEvent = { type: 'end' }; 131 | 132 | this.rotateLeft = function ( angle ) { 133 | 134 | if ( angle === undefined ) { 135 | 136 | angle = getAutoRotationAngle(); 137 | 138 | } 139 | 140 | thetaDelta -= angle; 141 | 142 | }; 143 | 144 | this.rotateUp = function ( angle ) { 145 | 146 | if ( angle === undefined ) { 147 | 148 | angle = getAutoRotationAngle(); 149 | 150 | } 151 | 152 | phiDelta -= angle; 153 | 154 | }; 155 | 156 | // pass in distance in world space to move left 157 | this.panLeft = function ( distance ) { 158 | 159 | var te = this.object.matrix.elements; 160 | 161 | // get X column of matrix 162 | panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] ); 163 | panOffset.multiplyScalar( - distance ); 164 | 165 | pan.add( panOffset ); 166 | 167 | }; 168 | 169 | // pass in distance in world space to move up 170 | this.panUp = function ( distance ) { 171 | 172 | var te = this.object.matrix.elements; 173 | 174 | // get Y column of matrix 175 | panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] ); 176 | panOffset.multiplyScalar( distance ); 177 | 178 | pan.add( panOffset ); 179 | 180 | }; 181 | 182 | // pass in x,y of change desired in pixel space, 183 | // right and down are positive 184 | this.pan = function ( deltaX, deltaY ) { 185 | 186 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 187 | 188 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 189 | 190 | // perspective 191 | var position = scope.object.position; 192 | var offset = position.clone().sub( scope.target ); 193 | var targetDistance = offset.length(); 194 | 195 | // half of the fov is center to top of screen 196 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 ); 197 | 198 | // we actually don't use screenWidth, since perspective camera is fixed to screen height 199 | scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight ); 200 | scope.panUp( 2 * deltaY * targetDistance / element.clientHeight ); 201 | 202 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 203 | 204 | // orthographic 205 | scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth ); 206 | scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight ); 207 | 208 | } else { 209 | 210 | // camera neither orthographic or perspective 211 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); 212 | 213 | } 214 | 215 | }; 216 | 217 | this.dollyIn = function ( dollyScale ) { 218 | 219 | if ( dollyScale === undefined ) { 220 | 221 | dollyScale = getZoomScale(); 222 | 223 | } 224 | 225 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 226 | 227 | scale /= dollyScale; 228 | 229 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 230 | 231 | scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) ); 232 | scope.object.updateProjectionMatrix(); 233 | scope.dispatchEvent( changeEvent ); 234 | 235 | } else { 236 | 237 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 238 | 239 | } 240 | 241 | }; 242 | 243 | this.dollyOut = function ( dollyScale ) { 244 | 245 | if ( dollyScale === undefined ) { 246 | 247 | dollyScale = getZoomScale(); 248 | 249 | } 250 | 251 | if ( scope.object instanceof THREE.PerspectiveCamera ) { 252 | 253 | scale *= dollyScale; 254 | 255 | } else if ( scope.object instanceof THREE.OrthographicCamera ) { 256 | 257 | scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) ); 258 | scope.object.updateProjectionMatrix(); 259 | scope.dispatchEvent( changeEvent ); 260 | 261 | } else { 262 | 263 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); 264 | 265 | } 266 | 267 | }; 268 | 269 | this.update = function () { 270 | 271 | var position = this.object.position; 272 | 273 | offset.copy( position ).sub( this.target ); 274 | 275 | // rotate offset to "y-axis-is-up" space 276 | offset.applyQuaternion( quat ); 277 | 278 | // angle from z-axis around y-axis 279 | 280 | theta = Math.atan2( offset.x, offset.z ); 281 | 282 | // angle from y-axis 283 | 284 | phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); 285 | 286 | if ( this.autoRotate && state === STATE.NONE ) { 287 | 288 | this.rotateLeft( getAutoRotationAngle() ); 289 | 290 | } 291 | 292 | theta += thetaDelta; 293 | phi += phiDelta; 294 | 295 | // restrict theta to be between desired limits 296 | theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) ); 297 | 298 | // restrict phi to be between desired limits 299 | phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); 300 | 301 | // restrict phi to be betwee EPS and PI-EPS 302 | phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); 303 | 304 | var radius = offset.length() * scale; 305 | 306 | // restrict radius to be between desired limits 307 | radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); 308 | 309 | // move target to panned location 310 | this.target.add( pan ); 311 | 312 | offset.x = radius * Math.sin( phi ) * Math.sin( theta ); 313 | offset.y = radius * Math.cos( phi ); 314 | offset.z = radius * Math.sin( phi ) * Math.cos( theta ); 315 | 316 | // rotate offset back to "camera-up-vector-is-up" space 317 | offset.applyQuaternion( quatInverse ); 318 | 319 | position.copy( this.target ).add( offset ); 320 | 321 | this.object.lookAt( this.target ); 322 | 323 | thetaDelta = 0; 324 | phiDelta = 0; 325 | scale = 1; 326 | pan.set( 0, 0, 0 ); 327 | 328 | // update condition is: 329 | // min(camera displacement, camera rotation in radians)^2 > EPS 330 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8 331 | 332 | if ( lastPosition.distanceToSquared( this.object.position ) > EPS 333 | || 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS ) { 334 | 335 | this.dispatchEvent( changeEvent ); 336 | 337 | lastPosition.copy( this.object.position ); 338 | lastQuaternion.copy (this.object.quaternion ); 339 | 340 | } 341 | 342 | }; 343 | 344 | 345 | this.reset = function () { 346 | 347 | state = STATE.NONE; 348 | 349 | this.target.copy( this.target0 ); 350 | this.object.position.copy( this.position0 ); 351 | this.object.zoom = this.zoom0; 352 | 353 | this.object.updateProjectionMatrix(); 354 | this.dispatchEvent( changeEvent ); 355 | 356 | this.update(); 357 | 358 | }; 359 | 360 | this.getPolarAngle = function () { 361 | 362 | return phi; 363 | 364 | }; 365 | 366 | this.getAzimuthalAngle = function () { 367 | 368 | return theta 369 | 370 | }; 371 | 372 | function getAutoRotationAngle() { 373 | 374 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 375 | 376 | } 377 | 378 | function getZoomScale() { 379 | 380 | return Math.pow( 0.95, scope.zoomSpeed ); 381 | 382 | } 383 | 384 | function onMouseDown( event ) { 385 | 386 | if ( scope.enabled === false ) return; 387 | event.preventDefault(); 388 | 389 | if ( event.button === scope.mouseButtons.ORBIT ) { 390 | if ( scope.noRotate === true ) return; 391 | 392 | state = STATE.ROTATE; 393 | 394 | rotateStart.set( event.clientX, event.clientY ); 395 | 396 | } else if ( event.button === scope.mouseButtons.ZOOM ) { 397 | if ( scope.noZoom === true ) return; 398 | 399 | state = STATE.DOLLY; 400 | 401 | dollyStart.set( event.clientX, event.clientY ); 402 | 403 | } else if ( event.button === scope.mouseButtons.PAN ) { 404 | if ( scope.noPan === true ) return; 405 | 406 | state = STATE.PAN; 407 | 408 | panStart.set( event.clientX, event.clientY ); 409 | 410 | } 411 | 412 | if ( state !== STATE.NONE ) { 413 | document.addEventListener( 'mousemove', onMouseMove, false ); 414 | document.addEventListener( 'mouseup', onMouseUp, false ); 415 | scope.dispatchEvent( startEvent ); 416 | } 417 | 418 | } 419 | 420 | function onMouseMove( event ) { 421 | 422 | if ( scope.enabled === false ) return; 423 | 424 | event.preventDefault(); 425 | 426 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 427 | 428 | if ( state === STATE.ROTATE ) { 429 | 430 | if ( scope.noRotate === true ) return; 431 | 432 | rotateEnd.set( event.clientX, event.clientY ); 433 | rotateDelta.subVectors( rotateEnd, rotateStart ); 434 | 435 | // rotating across whole screen goes 360 degrees around 436 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 437 | 438 | // rotating up and down along whole screen attempts to go 360, but limited to 180 439 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 440 | 441 | rotateStart.copy( rotateEnd ); 442 | 443 | } else if ( state === STATE.DOLLY ) { 444 | 445 | if ( scope.noZoom === true ) return; 446 | 447 | dollyEnd.set( event.clientX, event.clientY ); 448 | dollyDelta.subVectors( dollyEnd, dollyStart ); 449 | 450 | if ( dollyDelta.y > 0 ) { 451 | 452 | scope.dollyIn(); 453 | 454 | } else if ( dollyDelta.y < 0 ) { 455 | 456 | scope.dollyOut(); 457 | 458 | } 459 | 460 | dollyStart.copy( dollyEnd ); 461 | 462 | } else if ( state === STATE.PAN ) { 463 | 464 | if ( scope.noPan === true ) return; 465 | 466 | panEnd.set( event.clientX, event.clientY ); 467 | panDelta.subVectors( panEnd, panStart ); 468 | 469 | scope.pan( panDelta.x, panDelta.y ); 470 | 471 | panStart.copy( panEnd ); 472 | 473 | } 474 | 475 | if ( state !== STATE.NONE ) scope.update(); 476 | 477 | } 478 | 479 | function onMouseUp( /* event */ ) { 480 | 481 | if ( scope.enabled === false ) return; 482 | 483 | document.removeEventListener( 'mousemove', onMouseMove, false ); 484 | document.removeEventListener( 'mouseup', onMouseUp, false ); 485 | scope.dispatchEvent( endEvent ); 486 | state = STATE.NONE; 487 | 488 | } 489 | 490 | function onMouseWheel( event ) { 491 | 492 | if ( scope.enabled === false || scope.noZoom === true || state !== STATE.NONE ) return; 493 | 494 | event.preventDefault(); 495 | event.stopPropagation(); 496 | 497 | var delta = 0; 498 | 499 | if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9 500 | 501 | delta = event.wheelDelta; 502 | 503 | } else if ( event.detail !== undefined ) { // Firefox 504 | 505 | delta = - event.detail; 506 | 507 | } 508 | 509 | if ( delta > 0 ) { 510 | 511 | scope.dollyOut(); 512 | 513 | } else if ( delta < 0 ) { 514 | 515 | scope.dollyIn(); 516 | 517 | } 518 | 519 | scope.update(); 520 | scope.dispatchEvent( startEvent ); 521 | scope.dispatchEvent( endEvent ); 522 | 523 | } 524 | 525 | function onKeyDown( event ) { 526 | 527 | if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return; 528 | 529 | switch ( event.keyCode ) { 530 | 531 | case scope.keys.UP: 532 | scope.pan( 0, scope.keyPanSpeed ); 533 | scope.update(); 534 | break; 535 | 536 | case scope.keys.BOTTOM: 537 | scope.pan( 0, - scope.keyPanSpeed ); 538 | scope.update(); 539 | break; 540 | 541 | case scope.keys.LEFT: 542 | scope.pan( scope.keyPanSpeed, 0 ); 543 | scope.update(); 544 | break; 545 | 546 | case scope.keys.RIGHT: 547 | scope.pan( - scope.keyPanSpeed, 0 ); 548 | scope.update(); 549 | break; 550 | 551 | } 552 | 553 | } 554 | 555 | function touchstart( event ) { 556 | 557 | if ( scope.enabled === false ) return; 558 | 559 | switch ( event.touches.length ) { 560 | 561 | case 1: // one-fingered touch: rotate 562 | 563 | if ( scope.noRotate === true ) return; 564 | 565 | state = STATE.TOUCH_ROTATE; 566 | 567 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 568 | break; 569 | 570 | case 2: // two-fingered touch: dolly 571 | 572 | if ( scope.noZoom === true ) return; 573 | 574 | state = STATE.TOUCH_DOLLY; 575 | 576 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 577 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 578 | var distance = Math.sqrt( dx * dx + dy * dy ); 579 | dollyStart.set( 0, distance ); 580 | break; 581 | 582 | case 3: // three-fingered touch: pan 583 | 584 | if ( scope.noPan === true ) return; 585 | 586 | state = STATE.TOUCH_PAN; 587 | 588 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 589 | break; 590 | 591 | default: 592 | 593 | state = STATE.NONE; 594 | 595 | } 596 | 597 | if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent ); 598 | 599 | } 600 | 601 | function touchmove( event ) { 602 | 603 | if ( scope.enabled === false ) return; 604 | 605 | event.preventDefault(); 606 | event.stopPropagation(); 607 | 608 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 609 | 610 | switch ( event.touches.length ) { 611 | 612 | case 1: // one-fingered touch: rotate 613 | 614 | if ( scope.noRotate === true ) return; 615 | if ( state !== STATE.TOUCH_ROTATE ) return; 616 | 617 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 618 | rotateDelta.subVectors( rotateEnd, rotateStart ); 619 | 620 | // rotating across whole screen goes 360 degrees around 621 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 622 | // rotating up and down along whole screen attempts to go 360, but limited to 180 623 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 624 | 625 | rotateStart.copy( rotateEnd ); 626 | 627 | scope.update(); 628 | break; 629 | 630 | case 2: // two-fingered touch: dolly 631 | 632 | if ( scope.noZoom === true ) return; 633 | if ( state !== STATE.TOUCH_DOLLY ) return; 634 | 635 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 636 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 637 | var distance = Math.sqrt( dx * dx + dy * dy ); 638 | 639 | dollyEnd.set( 0, distance ); 640 | dollyDelta.subVectors( dollyEnd, dollyStart ); 641 | 642 | if ( dollyDelta.y > 0 ) { 643 | 644 | scope.dollyOut(); 645 | 646 | } else if ( dollyDelta.y < 0 ) { 647 | 648 | scope.dollyIn(); 649 | 650 | } 651 | 652 | dollyStart.copy( dollyEnd ); 653 | 654 | scope.update(); 655 | break; 656 | 657 | case 3: // three-fingered touch: pan 658 | 659 | if ( scope.noPan === true ) return; 660 | if ( state !== STATE.TOUCH_PAN ) return; 661 | 662 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 663 | panDelta.subVectors( panEnd, panStart ); 664 | 665 | scope.pan( panDelta.x, panDelta.y ); 666 | 667 | panStart.copy( panEnd ); 668 | 669 | scope.update(); 670 | break; 671 | 672 | default: 673 | 674 | state = STATE.NONE; 675 | 676 | } 677 | 678 | } 679 | 680 | function touchend( /* event */ ) { 681 | 682 | if ( scope.enabled === false ) return; 683 | 684 | scope.dispatchEvent( endEvent ); 685 | state = STATE.NONE; 686 | 687 | } 688 | 689 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); 690 | this.domElement.addEventListener( 'mousedown', onMouseDown, false ); 691 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); 692 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox 693 | 694 | this.domElement.addEventListener( 'touchstart', touchstart, false ); 695 | this.domElement.addEventListener( 'touchend', touchend, false ); 696 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 697 | 698 | window.addEventListener( 'keydown', onKeyDown, false ); 699 | 700 | // force an update at start 701 | this.update(); 702 | 703 | }; 704 | 705 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 706 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls; -------------------------------------------------------------------------------- /examples/data/scatter.js: -------------------------------------------------------------------------------- 1 | 2 | window.nations=[ 3 | 4 | 5 | { "name":"Angola","region":"Sub-Saharan Africa","income":[[2009,5055.59]],"population":[[2009,12707546]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,47.58]]}, 6 | { 7 | "name":"Benin","region":"Sub-Saharan Africa","income":[[2009,1457.57]],"population":[[2009,8294941]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,61.89]]}, 8 | { 9 | "name":"Botswana","region":"Sub-Saharan Africa","income":[[2009,12282.28]],"population":[[2009,1638393]],"unemployment":[[2009,8.100000381]],"lifeExpectancy":[[2009,55.12]]}, 10 | { 11 | "name":"Burkina Faso","region":"Sub-Saharan Africa","income":[[2009,1234.42]],"population":[[2009,14761339]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,53.38]]}, 12 | { 13 | "name":"Burundi","region":"Sub-Saharan Africa","income":[[2009,457.07]],"population":[[2009,8691005]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,50.95]]}, 14 | { 15 | "name":"Cameroon","region":"Sub-Saharan Africa","income":[[2009,1997.18]],"population":[[2009,18054929]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,51.39]]}, 16 | { 17 | "name":"Cape Verde","region":"Sub-Saharan Africa","income":[[2009,3456.14]],"population":[[2009,426113]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.68]]}, 18 | { 19 | "name":"Chad","region":"Sub-Saharan Africa","income":[[2009,1557.83]],"population":[[2009,10541156]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,48.97]]}, 20 | { 21 | "name":"Comoros","region":"Sub-Saharan Africa","income":[[2009,1016.42]],"population":[[2009,731281]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,65.77]]}, 22 | { 23 | "name":"Congo, Dem. Rep.","region":"Sub-Saharan Africa","income":[[2009,358.8]],"population":[[2009,66604314]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,47.81]]}, 24 | { 25 | "name":"Congo, Rep.","region":"Sub-Saharan Africa","income":[[2009,3834.67]],"population":[[2009,3903318]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,53.75]]}, 26 | { 27 | "name":"Cote d'Ivoire","region":"Sub-Saharan Africa","income":[[2009,1520.23]],"population":[[2009,18373060]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,57.86]]}, 28 | { 29 | "name":"Equatorial Guinea","region":"Sub-Saharan Africa","income":[[2009,15342.2]],"population":[[2009,562339]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,50.64]]}, 30 | { 31 | "name":"Eritrea","region":"Sub-Saharan Africa","income":[[2009,548.37]],"population":[[2009,5028475]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,60.03]]}, 32 | { 33 | "name":"Ethiopia","region":"Sub-Saharan Africa","income":[[2009,812.16]],"population":[[2009,78254090]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,55.69]]}, 34 | { 35 | "name":"Gabon","region":"Sub-Saharan Africa","income":[[2009,12704.99]],"population":[[2009,1484149]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,60.89]]}, 36 | { 37 | "name":"Ghana","region":"Sub-Saharan Africa","income":[[2009,1382.95]],"population":[[2009,23336661]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,56.83]]}, 38 | { 39 | "name":"Guinea","region":"Sub-Saharan Africa","income":[[2009,908.86]],"population":[[2009,10211437]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,58.35]]}, 40 | { 41 | "name":"Guinea-Bissau","region":"Sub-Saharan Africa","income":[[2009,568.94]],"population":[[2009,1502442]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,48.2]]}, 42 | { 43 | "name":"Kenya","region":"Sub-Saharan Africa","income":[[2009,1493.53]],"population":[[2009,36529155]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,54.95]]}, 44 | { 45 | "name":"Lesotho","region":"Sub-Saharan Africa","income":[[2009,1521.4]],"population":[[2009,2002749]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,45.56]]}, 46 | { 47 | "name":"Liberia","region":"Sub-Saharan Africa","income":[[2009,474.9]],"population":[[2009,3332483]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,58.71]]}, 48 | { 49 | "name":"Madagascar","region":"Sub-Saharan Africa","income":[[2009,1006.9]],"population":[[2009,19757525]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,60.81]]}, 50 | { 51 | "name":"Malawi","region":"Sub-Saharan Africa","income":[[2009,866.35]],"population":[[2009,13647273]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,53.88]]}, 52 | { 53 | "name":"Mali","region":"Sub-Saharan Africa","income":[[2009,1136.17]],"population":[[2009,12360306]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,48.84]]}, 54 | { 55 | "name":"Mauritania","region":"Sub-Saharan Africa","income":[[2009,1775.87]],"population":[[2009,3364940]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,56.99]]}, 56 | { 57 | "name":"Mauritius","region":"Sub-Saharan Africa","income":[[2009,11411.53]],"population":[[2009,1260781]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.1]]}, 58 | { 59 | "name":"Mayotte","region":"Sub-Saharan Africa","income":[[2005,9617.82]],"population":[[2009,216334]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.99]]}, 60 | { 61 | "name":"Mozambique","region":"Sub-Saharan Africa","income":[[2009,888.65]],"population":[[2009,20203186]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,48.13]]}, 62 | { 63 | "name":"Namibia","region":"Sub-Saharan Africa","income":[[2009,4952.26]],"population":[[2009,2063927]],"unemployment":[[2009,10.89999962]],"lifeExpectancy":[[2009,61.72]]}, 64 | { 65 | "name":"Niger","region":"Sub-Saharan Africa","income":[[2009,643.39]],"population":[[2009,13272679]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,51.95]]}, 66 | { 67 | "name":"Nigeria","region":"Sub-Saharan Africa","income":[[2009,2158.98]],"population":[[2009,138283240]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,48.17]]}, 68 | { 69 | "name":"Reunion","region":"Sub-Saharan Africa","income":[[2007,7670.12]],"population":[[2009,808506]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,76.64]]}, 70 | { 71 | "name":"Rwanda","region":"Sub-Saharan Africa","income":[[2009,995.27]],"population":[[2009,9077425]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,50.69]]}, 72 | { 73 | "name":"Sao Tome and Principe","region":"Sub-Saharan Africa","income":[[2009,1703.43]],"population":[[2009,205901]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,65.86]]}, 74 | { 75 | "name":"Senegal","region":"Sub-Saharan Africa","income":[[2009,1700.05]],"population":[[2009,12548243]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,55.91]]}, 76 | { 77 | "name":"Sierra Leone","region":"Sub-Saharan Africa","income":[[2009,893.6]],"population":[[2009,6286617]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,47.95]]}, 78 | { 79 | "name":"Somalia","region":"Sub-Saharan Africa","income":[[2009,943.04]],"population":[[2009,9379907]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,50.09]]}, 80 | { 81 | "name":"South Africa","region":"Sub-Saharan Africa","income":[[2009,9141.27]],"population":[[2009,43786115]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,51.72]]}, 82 | { 83 | "name":"Sudan","region":"Sub-Saharan Africa","income":[[2009,2778.61]],"population":[[2009,43354411]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,58.5]]}, 84 | { 85 | "name":"Swaziland","region":"Sub-Saharan Africa","income":[[2009,4728.18]],"population":[[2009,1128814]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,46.36]]}, 86 | { 87 | "name":"Tanzania","region":"Sub-Saharan Africa","income":[[2009,1220.25]],"population":[[2009,38858276]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,56.35]]}, 88 | { 89 | "name":"Togo","region":"Sub-Saharan Africa","income":[[2009,888.01]],"population":[[2009,5858673]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,62.93]]}, 90 | { 91 | "name":"Uganda","region":"Sub-Saharan Africa","income":[[2009,1202.53]],"population":[[2009,30214531]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,53.47]]}, 92 | { 93 | "name":"Zambia","region":"Sub-Saharan Africa","income":[[2009,1442.06]],"population":[[2009,11993403]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,46.4]]}, 94 | { 95 | "name":"Zimbabwe","region":"Sub-Saharan Africa","income":[[2009,443.74]],"population":[[2009,12382920]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,45.72]]}, 96 | { 97 | "name":"Afghanistan","region":"South Asia","income":[[2009,1216.68]],"population":[[2009,32738376]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,44.3]]}, 98 | { 99 | "name":"Bangladesh","region":"South Asia","income":[[2009,1492]],"population":[[2009,153546901]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,66.56]]}, 100 | { 101 | "name":"Bhutan","region":"South Asia","income":[[2009,5053.83]],"population":[[2009,2376680]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,66.42]]}, 102 | { 103 | "name":"India","region":"South Asia","income":[[2009,2731]],"population":[[2009,1125368288]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,64.01]]}, 104 | { 105 | "name":"Maldives","region":"South Asia","income":[[2009,5081.79]],"population":[[2009,379174]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.94]]}, 106 | { 107 | "name":"Nepal","region":"South Asia","income":[[2009,1224.73]],"population":[[2009,29519114]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,67.12]]}, 108 | { 109 | "name":"Pakistan","region":"South Asia","income":[[2009,2603]],"population":[[2009,172730891]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,66.84]]}, 110 | { 111 | "name":"Sri Lanka","region":"South Asia","income":[[2009,4254.13]],"population":[[2009,20532150]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.24]]}, 112 | { 113 | "name":"Algeria","region":"Middle East & North Africa","income":[[2009,6207.17]],"population":[[2009,33739635]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.67]]}, 114 | { 115 | "name":"Bahrain","region":"Middle East & North Africa","income":[[2009,24226.51]],"population":[[2009,718306]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.88]]}, 116 | { 117 | "name":"Djibouti","region":"Middle East & North Africa","income":[[2009,2176.79]],"population":[[2009,506221]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,55.78]]}, 118 | { 119 | "name":"Iraq","region":"Middle East & North Africa","income":[[2009,3518.18]],"population":[[2009,28221181]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,68.1]]}, 120 | { 121 | "name":"Israel","region":"Middle East & North Africa","income":[[2009,25463.69]],"population":[[2009,6500389]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,81]]}, 122 | { 123 | "name":"Jordan","region":"Middle East & North Africa","income":[[2009,5109.39]],"population":[[2009,6198677]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.88]]}, 124 | { 125 | "name":"Kuwait","region":"Middle East & North Africa","income":[[2009,42443.53]],"population":[[2009,2596799]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,77.79]]}, 126 | { 127 | "name":"Lebanon","region":"Middle East & North Africa","income":[[2009,12766.21]],"population":[[2009,3967467]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.26]]}, 128 | { 129 | "name":"Libya","region":"Middle East & North Africa","income":[[2009,12051.62]],"population":[[2009,6173579]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.28]]}, 130 | { 131 | "name":"Morocco","region":"Middle East & North Africa","income":[[2009,4162.93]],"population":[[2009,34272968]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.58]]}, 132 | { 133 | "name":"Oman","region":"Middle East & North Africa","income":[[2009,22804.85]],"population":[[2009,3309440]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.94]]}, 134 | { 135 | "name":"Qatar","region":"Middle East & North Africa","income":[[2009,74138.28]],"population":[[2009,928635]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.81]]}, 136 | { 137 | "name":"Saudi Arabia","region":"Middle East & North Africa","income":[[2009,21138.18]],"population":[[2009,28161417]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.1]]}, 138 | { 139 | "name":"Tunisia","region":"Middle East & North Africa","income":[[2009,7499.61]],"population":[[2009,10378140]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.15]]}, 140 | { 141 | "name":"United Arab Emirates","region":"Middle East & North Africa","income":[[2009,33734.94]],"population":[[2009,2682747]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,77.58]]}, 142 | { 143 | "name":"West Bank and Gaza","region":"Middle East & North Africa","income":[[2009,3084.56]],"population":[[2009,4149173]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.74]]}, 144 | { 145 | "name":"Yemen, Rep.","region":"Middle East & North Africa","income":[[2009,2313.16]],"population":[[2009,22993911]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,63.39]]}, 146 | { 147 | "name":"Argentina","region":"America","income":[[2009,13498.04]],"population":[[2009,40677348]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.52]]}, 148 | { 149 | "name":"Aruba","region":"America","income":[[2009,25351.09]],"population":[[2009,72480]],"unemployment":[[2009,2.400000095]],"lifeExpectancy":[[2009,74.92]]}, 150 | { 151 | "name":"Barbados","region":"America","income":[[2009,15846.77]],"population":[[2009,281968]],"unemployment":[[2009,4.599999905]],"lifeExpectancy":[[2009,77.51]]}, 152 | { 153 | "name":"Belize","region":"America","income":[[2009,6998.08]],"population":[[2009,301022]],"unemployment":[[2009,6.900000095]],"lifeExpectancy":[[2009,76.6]]}, 154 | { 155 | "name":"Bolivia","region":"America","income":[[2009,4007.16]],"population":[[2009,9247816]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,66.01]]}, 156 | { 157 | "name":"Brazil","region":"America","income":[[2009,9569.78]],"population":[[2009,191908598]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.68]]}, 158 | { 159 | "name":"Canada","region":"America","income":[[2009,34569.63]],"population":[[2009,33679263]],"unemployment":[[2009,0.400000006]],"lifeExpectancy":[[2009,80.89]]}, 160 | { 161 | "name":"Chile","region":"America","income":[[2009,13087.38]],"population":[[2009,16432536]],"unemployment":[[2009,3.400000095]],"lifeExpectancy":[[2009,78.67]]}, 162 | { 163 | "name":"Colombia","region":"America","income":[[2009,7090.69]],"population":[[2009,44858264]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.19]]}, 164 | { 165 | "name":"Costa Rica","region":"America","income":[[2009,9551.56]],"population":[[2009,4191948]],"unemployment":[[2009,0.699999988]],"lifeExpectancy":[[2009,78.98]]}, 166 | { 167 | "name":"Cuba","region":"America","income":[[2009,9277.96]],"population":[[2009,11449006]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,78.84]]}, 168 | { 169 | "name":"Ecuador","region":"America","income":[[2009,7035.45]],"population":[[2009,13927650]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.26]]}, 170 | { 171 | "name":"El Salvador","region":"America","income":[[2009,5646.85]],"population":[[2009,7057131]],"unemployment":[[2009,0.600000024]],"lifeExpectancy":[[2009,71.74]]}, 172 | { 173 | "name":"French Guiana","region":"America","income":[[2005,8202.74]],"population":[[2009,206941]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,76.16]]}, 174 | { 175 | "name":"Grenada","region":"America","income":[[2009,8826.9]],"population":[[2009,90303]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.62]]}, 176 | { 177 | "name":"Guadeloupe","region":"America","income":[[2005,7788.25]],"population":[[2009,460486]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,79.28]]}, 178 | { 179 | "name":"Guatemala","region":"America","income":[[2009,5163.22]],"population":[[2009,12851647]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,70.55]]}, 180 | { 181 | "name":"Guyana","region":"America","income":[[2009,3776.95]],"population":[[2009,770794]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,67.43]]}, 182 | { 183 | "name":"Haiti","region":"America","income":[[2009,1198.05]],"population":[[2009,8704413]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,61.48]]}, 184 | { 185 | "name":"Honduras","region":"America","income":[[2009,3473.46]],"population":[[2009,7639327]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.41]]}, 186 | { 187 | "name":"Jamaica","region":"America","income":[[2009,7023.74]],"population":[[2009,2801544]],"unemployment":[[2009,4.800000191]],"lifeExpectancy":[[2009,72.11]]}, 188 | { 189 | "name":"Martinique","region":"America","income":[[2005,14627.13]],"population":[[2009,442119]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,79.77]]}, 190 | { 191 | "name":"Mexico","region":"America","income":[[2009,11250.37]],"population":[[2009,109955400]],"unemployment":[[2009,0.100000001]],"lifeExpectancy":[[2009,76.47]]}, 192 | { 193 | "name":"Netherlands Antilles","region":"America","income":[[2009,23178.37]],"population":[[2009,225168]],"unemployment":[[2009,8.399999619]],"lifeExpectancy":[[2009,76.38]]}, 194 | { 195 | "name":"Nicaragua","region":"America","income":[[2009,2591.39]],"population":[[2009,5780586]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.44]]}, 196 | { 197 | "name":"Panama","region":"America","income":[[2009,10796.68]],"population":[[2009,3292693]],"unemployment":[[2009,3.599999905]],"lifeExpectancy":[[2009,75.81]]}, 198 | { 199 | "name":"Paraguay","region":"America","income":[[2009,4054.3]],"population":[[2009,6829969]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.07]]}, 200 | { 201 | "name":"Peru","region":"America","income":[[2009,7858.97]],"population":[[2009,29041593]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.47]]}, 202 | { 203 | "name":"Puerto Rico","region":"America","income":[[2009,18970.51]],"population":[[2009,3957169]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,78.95]]}, 204 | { 205 | "name":"Suriname","region":"America","income":[[2009,8199.03]],"population":[[2009,440486]],"unemployment":[[2009,4.400000095]],"lifeExpectancy":[[2009,69.16]]}, 206 | { 207 | "name":"Trinidad and Tobago","region":"America","income":[[2009,17826.05]],"population":[[2009,1047366]],"unemployment":[[2009,3]],"lifeExpectancy":[[2009,69.7]]}, 208 | { 209 | "name":"United States","region":"America","income":[[2009,41256.08]],"population":[[2009,303824646]],"unemployment":[[2009,0.5]],"lifeExpectancy":[[2009,79.43]]}, 210 | { 211 | "name":"Uruguay","region":"America","income":[[2009,11461.03]],"population":[[2009,3462531]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,76.5]]}, 212 | { 213 | "name":"Albania","region":"Europe & Central Asia","income":[[2009,6546.27]],"population":[[2009,3619778]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,76.74]]}, 214 | { 215 | "name":"Armenia","region":"Europe & Central Asia","income":[[2009,4523.44]],"population":[[2009,2968586]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.03]]}, 216 | { 217 | "name":"Austria","region":"Europe & Central Asia","income":[[2009,35636.42]],"population":[[2009,8205533]],"unemployment":[[2009,1.200000048]],"lifeExpectancy":[[2009,80.23]]}, 218 | { 219 | "name":"Azerbaijan","region":"Europe & Central Asia","income":[[2009,9088.42]],"population":[[2009,8079043]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,70.6]]}, 220 | { 221 | "name":"Belarus","region":"Europe & Central Asia","income":[[2009,11574.43]],"population":[[2009,10287955]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,69.4]]}, 222 | { 223 | "name":"Belgium","region":"Europe & Central Asia","income":[[2009,32256.64]],"population":[[2009,10403951]],"unemployment":[[2009,3.799999952]],"lifeExpectancy":[[2009,80.05]]}, 224 | { 225 | "name":"Bosnia and Herzegovina","region":"Europe & Central Asia","income":[[2009,7341.98]],"population":[[2009,4590310]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,75.34]]}, 226 | { 227 | "name":"Bulgaria","region":"Europe & Central Asia","income":[[2009,10840.26]],"population":[[2009,7262675]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.53]]}, 228 | { 229 | "name":"Croatia","region":"Europe & Central Asia","income":[[2009,14110.46]],"population":[[2009,4491543]],"unemployment":[[2009,8.600000381]],"lifeExpectancy":[[2009,76.49]]}, 230 | { 231 | "name":"Cyprus","region":"Europe & Central Asia","income":[[2009,25643.45]],"population":[[2009,792604]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,79.85]]}, 232 | { 233 | "name":"Denmark","region":"Europe & Central Asia","income":[[2009,32670.06]],"population":[[2009,5484723]],"unemployment":[[2009,0.699999988]],"lifeExpectancy":[[2009,78.57]]}, 234 | { 235 | "name":"Estonia","region":"Europe & Central Asia","income":[[2009,16349.13]],"population":[[2009,1307605]],"unemployment":[[2009,4.599999905]],"lifeExpectancy":[[2009,73.5]]}, 236 | { 237 | "name":"Finland","region":"Europe & Central Asia","income":[[2009,30602.73]],"population":[[2009,5244749]],"unemployment":[[2009,1.5]],"lifeExpectancy":[[2009,79.9]]}, 238 | { 239 | "name":"France","region":"Europe & Central Asia","income":[[2009,29774.85]],"population":[[2009,61279972]],"unemployment":[[2009,3.099999905]],"lifeExpectancy":[[2009,81.47]]}, 240 | { 241 | "name":"Georgia","region":"Europe & Central Asia","income":[[2009,4168.7]],"population":[[2009,4630841]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.86]]}, 242 | { 243 | "name":"Germany","region":"Europe & Central Asia","income":[[2009,31191.15]],"population":[[2009,82369548]],"unemployment":[[2009,4.800000191]],"lifeExpectancy":[[2009,80.08]]}, 244 | { 245 | "name":"Greece","region":"Europe & Central Asia","income":[[2009,27626.11]],"population":[[2009,10722816]],"unemployment":[[2009,4.099999905]],"lifeExpectancy":[[2009,79.5]]}, 246 | { 247 | "name":"Hungary","region":"Europe & Central Asia","income":[[2009,16982.8]],"population":[[2009,9930915]],"unemployment":[[2009,3.5]],"lifeExpectancy":[[2009,73.67]]}, 248 | { 249 | "name":"Iceland","region":"Europe & Central Asia","income":[[2009,34989.73]],"population":[[2009,304367]],"unemployment":[[2009,0.100000001]],"lifeExpectancy":[[2009,81.95]]}, 250 | { 251 | "name":"Ireland","region":"Europe & Central Asia","income":[[2009,35692.95]],"population":[[2009,4156119]],"unemployment":[[2009,1.399999976]],"lifeExpectancy":[[2009,80.16]]}, 252 | { 253 | "name":"Italy","region":"Europe & Central Asia","income":[[2009,26160.59]],"population":[[2009,58145321]],"unemployment":[[2009,2.799999952]],"lifeExpectancy":[[2009,81.34]]}, 254 | { 255 | "name":"Kazakhstan","region":"Europe & Central Asia","income":[[2009,10612.29]],"population":[[2009,15340533]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,65.18]]}, 256 | { 257 | "name":"Latvia","region":"Europe & Central Asia","income":[[2009,13021.94]],"population":[[2009,2245423]],"unemployment":[[2009,7.199999809]],"lifeExpectancy":[[2009,72.77]]}, 258 | { 259 | "name":"Lithuania","region":"Europe & Central Asia","income":[[2009,14928.78]],"population":[[2009,3565205]],"unemployment":[[2009,9.600000381]],"lifeExpectancy":[[2009,71.93]]}, 260 | { 261 | "name":"Luxembourg","region":"Europe & Central Asia","income":[[2009,70857.46]],"population":[[2009,486006]],"unemployment":[[2009,1.299999952]],"lifeExpectancy":[[2009,79.75]]}, 262 | { 263 | "name":"Macedonia, FYR","region":"Europe & Central Asia","income":[[2009,8364.79]],"population":[[2009,2061315]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.4]]}, 264 | { 265 | "name":"Malta","region":"Europe & Central Asia","income":[[2009,21327.85]],"population":[[2009,403532]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,79.91]]}, 266 | { 267 | "name":"Moldova","region":"Europe & Central Asia","income":[[2009,2593.42]],"population":[[2009,4496774]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,68.72]]}, 268 | { 269 | "name":"Montenegro","region":"Europe & Central Asia","income":[[2009,12257.79]],"population":[[2009,672180]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.34]]}, 270 | { 271 | "name":"Netherlands","region":"Europe & Central Asia","income":[[2009,36074.53]],"population":[[2009,16645313]],"unemployment":[[2009,1.299999952]],"lifeExpectancy":[[2009,80.19]]}, 272 | { 273 | "name":"Norway","region":"Europe & Central Asia","income":[[2009,47915]],"population":[[2009,4644457]],"unemployment":[[2009,0.200000003]],"lifeExpectancy":[[2009,80.85]]}, 274 | { 275 | "name":"Poland","region":"Europe & Central Asia","income":[[2009,16465.8]],"population":[[2009,38500696]],"unemployment":[[2009,4.400000095]],"lifeExpectancy":[[2009,75.84]]}, 276 | { 277 | "name":"Portugal","region":"Europe & Central Asia","income":[[2009,19898.43]],"population":[[2009,10676910]],"unemployment":[[2009,3.700000048]],"lifeExpectancy":[[2009,78.94]]}, 278 | { 279 | "name":"Romania","region":"Europe & Central Asia","income":[[2009,10868.12]],"population":[[2009,22246862]],"unemployment":[[2009,3.5]],"lifeExpectancy":[[2009,72.99]]}, 280 | { 281 | "name":"Serbia","region":"Europe & Central Asia","income":[[2009,10005.22]],"population":[[2009,10166507]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.23]]}, 282 | { 283 | "name":"Slovak Republic","region":"Europe & Central Asia","income":[[2009,19186.01]],"population":[[2009,5455407]],"unemployment":[[2009,7.800000191]],"lifeExpectancy":[[2009,74.94]]}, 284 | { 285 | "name":"Slovenia","region":"Europe & Central Asia","income":[[2009,24778.21]],"population":[[2009,2007711]],"unemployment":[[2009,3.900000095]],"lifeExpectancy":[[2009,78.63]]}, 286 | { 287 | "name":"Spain","region":"Europe & Central Asia","income":[[2009,26811.93]],"population":[[2009,40491051]],"unemployment":[[2009,2]],"lifeExpectancy":[[2009,81.11]]}, 288 | { 289 | "name":"Sweden","region":"Europe & Central Asia","income":[[2009,32021]],"population":[[2009,9045389]],"unemployment":[[2009,0.699999988]],"lifeExpectancy":[[2009,81.12]]}, 290 | { 291 | "name":"Switzerland","region":"Europe & Central Asia","income":[[2009,38003.92]],"population":[[2009,7581520]],"unemployment":[[2009,1.5]],"lifeExpectancy":[[2009,82.06]]}, 292 | { 293 | "name":"Tajikistan","region":"Europe & Central Asia","income":[[2009,1775.38]],"population":[[2009,7653394]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,67.07]]}, 294 | { 295 | "name":"Turkey","region":"Europe & Central Asia","income":[[2009,8040.78]],"population":[[2009,71892807]],"unemployment":[[2009,3]],"lifeExpectancy":[[2009,72.06]]}, 296 | { 297 | "name":"Turkmenistan","region":"Europe & Central Asia","income":[[2009,5702.66]],"population":[[2009,5232077]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,65.06]]}, 298 | { 299 | "name":"Ukraine","region":"Europe & Central Asia","income":[[2009,5730.86]],"population":[[2009,46170273]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,68.45]]}, 300 | { 301 | "name":"United Kingdom","region":"Europe & Central Asia","income":[[2009,31042.47]],"population":[[2009,60943912]],"unemployment":[[2009,1.299999952]],"lifeExpectancy":[[2009,79.64]]}, 302 | { 303 | "name":"Uzbekistan","region":"Europe & Central Asia","income":[[2009,2586.96]],"population":[[2009,28268440]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,67.97]]}, 304 | { 305 | "name":"Australia","region":"East Asia & Pacific","income":[[2009,34327.26]],"population":[[2009,20600856]],"unemployment":[[2009,0.699999988]],"lifeExpectancy":[[2009,81.71]]}, 306 | { 307 | "name":"Brunei","region":"East Asia & Pacific","income":[[2009,44738.99]],"population":[[2009,393551]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,77.32]]}, 308 | { 309 | "name":"Cambodia","region":"East Asia & Pacific","income":[[2009,1830.97]],"population":[[2009,14387642]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,61.67]]}, 310 | { 311 | "name":"China","region":"East Asia & Pacific","income":[[2009,7226.07]],"population":[[2009,1326856173]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,73.28]]}, 312 | { 313 | "name":"Fiji","region":"East Asia & Pacific","income":[[2009,4016.2]],"population":[[2009,931545]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,69.05]]}, 314 | { 315 | "name":"French Polynesia","region":"East Asia & Pacific","income":[[2009,26733.88]],"population":[[2009,282645]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.59]]}, 316 | { 317 | "name":"Hong Kong, China","region":"East Asia & Pacific","income":[[2009,39086.39]],"population":[[2009,7018636]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,82.4]]}, 318 | { 319 | "name":"Indonesia","region":"East Asia & Pacific","income":[[2009,3818.08]],"population":[[2009,226134000]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.17]]}, 320 | { 321 | "name":"Japan","region":"East Asia & Pacific","income":[[2009,29680.68]],"population":[[2009,127425722]],"unemployment":[[2009,1.200000048]],"lifeExpectancy":[[2009,82.98]]}, 322 | { 323 | "name":"Korea, Dem. Rep.","region":"East Asia & Pacific","income":[[2009,1635]],"population":[[2009,23479089]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,67.53]]}, 324 | { 325 | "name":"Korea, Rep.","region":"East Asia & Pacific","income":[[2009,23875]],"population":[[2009,49232844]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,79.65]]}, 326 | { 327 | "name":"Macao, China","region":"East Asia & Pacific","income":[[2009,57436.68]],"population":[[2009,460823]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,80.95]]}, 328 | { 329 | "name":"Malaysia","region":"East Asia & Pacific","income":[[2009,12387.67]],"population":[[2009,25259428]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.54]]}, 330 | { 331 | "name":"Micronesia, Fed. Sts.","region":"East Asia & Pacific","income":[[2009,4994.56]],"population":[[2009,107673]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,68.81]]}, 332 | { 333 | "name":"Mongolia","region":"East Asia & Pacific","income":[[2009,3205.17]],"population":[[2009,2916865]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,66.93]]}, 334 | { 335 | "name":"Myanmar","region":"East Asia & Pacific","income":[[2009,1269.14]],"population":[[2009,48133102]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,62.14]]}, 336 | { 337 | "name":"New Caledonia","region":"East Asia & Pacific","income":[[2009,30959.74]],"population":[[2009,224585]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,76.36]]}, 338 | { 339 | "name":"New Zealand","region":"East Asia & Pacific","income":[[2009,24009.46]],"population":[[2009,4154311]],"unemployment":[[2009,0.200000003]],"lifeExpectancy":[[2009,80.45]]}, 340 | { 341 | "name":"Papua New Guinea","region":"East Asia & Pacific","income":[[2009,1947.16]],"population":[[2009,5921144]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,61.29]]}, 342 | { 343 | "name":"Philippines","region":"East Asia & Pacific","income":[[2009,3203.97]],"population":[[2009,92681453]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,72.1]]}, 344 | { 345 | "name":"Samoa","region":"East Asia & Pacific","income":[[2009,5003.61]],"population":[[2009,176418]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.92]]}, 346 | { 347 | "name":"Singapore","region":"East Asia & Pacific","income":[[2009,43526.04]],"population":[[2009,4608167]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,80.58]]}, 348 | { 349 | "name":"Solomon Islands","region":"East Asia & Pacific","income":[[2009,1903.69]],"population":[[2009,581208]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,66.66]]}, 350 | { 351 | "name":"Taiwan","region":"East Asia & Pacific","income":[[2009,28361]],"population":[[2009,23308370]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,78.6]]}, 352 | { 353 | "name":"Thailand","region":"East Asia & Pacific","income":[[2009,7376.17]],"population":[[2009,65493298]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,69.08]]}, 354 | { 355 | "name":"Timor-Leste","region":"East Asia & Pacific","income":[[2009,2475.68]],"population":[[2009,1130120]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,61.6]]}, 356 | { 357 | "name":"Tokelau","region":"East Asia & Pacific","income":[[2005,889.43]],"population":[[2005,1401]],"unemployment":[[2009,0]],"lifeExpectancy":[[2006,69]]}, 358 | { 359 | "name":"Tonga","region":"East Asia & Pacific","income":[[2009,5104.06]],"population":[[2009,118993]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,71.96]]}, 360 | { 361 | "name":"Vietnam","region":"East Asia & Pacific","income":[[2009,2679.34]],"population":[[2009,86116559]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,74.7]]}, 362 | { 363 | "name":"Vanuatu","region":"East Asia & Pacific","income":[[2009,3943.3]],"population":[[2009,215053]],"unemployment":[[2009,0]],"lifeExpectancy":[[2009,70.5]]} 364 | ] -------------------------------------------------------------------------------- /examples/data/network.js: -------------------------------------------------------------------------------- 1 | 2 | var networkData = 3 | { 4 | "nodes": [ 5 | { "name": "Adra Systems", "group": 1 }, 6 | { "name": "Advanced Logic Research", "group": 1 }, 7 | { "name": "Alpha Micro Systems", "group": 1 }, 8 | { "name": "Altos Computer Systems", "group": 1 }, 9 | { "name": "Amdek", "group": 2 }, 10 | { "name": "Wyse", "group": 2 }, 11 | { "name": "American Research Corp.", "group": 2 }, 12 | { "name": "Apollo Computer", "group": 2 }, 13 | { "name": "Apple Computer", "group": 1 }, 14 | { "name": "Ardent Computer", "group": 1 }, 15 | { "name": "Arete Systems", "group": 1 }, 16 | { "name": "AST Research", "group": 1 }, 17 | { "name": "Atari", "group": 1 }, 18 | { "name": "BBN", "group": 1 }, 19 | { "name": "Cadnetix", "group":4}, 20 | { "name": "Calma", "group":1}, 21 | { "name": "Celerity Computing", "group":4}, 22 | { "name": "Charles River Data Systems", "group":4}, 23 | { "name": "ComputerVision", "group":1}, 24 | { "name": "Concurrent Computer Corp.", "group":4}, 25 | { "name": "Control Data Corporation", "group":1}, 26 | { "name": "Convergent Technologies", "group":1}, 27 | { "name": "Convex", "group":1}, 28 | { "name": "Corvus Systems Inc.", "group":1}, 29 | { "name": "CPT", "group":1}, 30 | { "name": "Daisy Systems", "group":1}, 31 | { "name": "Data General", "group":1}, 32 | { "name": "Data I/O", "group":1}, 33 | { "name": "DEC", "group":1}, 34 | { "name": "Harris Corp.", "group":8}, 35 | { "name": "Hewlett Packard", "group":8}, 36 | { "name": "IBM", "group":8}, 37 | { "name": "Intergraph", "group":8}, 38 | { "name": "Kontron Electronics", "group":8}, 39 | { "name": "Landmark Graphics Corp.", "group":8}, 40 | { "name": "Masscomp", "group":3}, 41 | { "name": "Honeywell Bull", "group":3}, 42 | { "name": "Mentor Graphics", "group":3}, 43 | { "name": "Metaphor Computer Systems", "group":3}, 44 | { "name": "MIPS Computer", "group":3}, 45 | { "name": "Mohawk Data Sciences", "group":3}, 46 | { "name": "Multiflow", "group":3}, 47 | { "name": "NBI", "group":3}, 48 | { "name": "NCR", "group":1}, 49 | { "name": "NEC", "group":1}, 50 | { "name": "Nixdorf", "group":1}, 51 | { "name": "OSHAP", "group":1}, 52 | { "name": "Paragon Technology", "group":1}, 53 | { "name": "Plexus Computers", "group":6}, 54 | { "name": "PRIME Computer", "group":6}, 55 | { "name": "Pyramid Technology", "group":6}, 56 | { "name": "Qubix", "group":1}, 57 | { "name": "Racal-Redac", "group":1}, 58 | { "name": "Ramtek", "group":1}, 59 | { "name": "Saber Technology", "group":5}, 60 | { "name": "Seiko Instruments", "group":5}, 61 | { "name": "Sequent Computer", "group":5}, 62 | { "name": "Silicon Graphics", "group":5}, 63 | { "name": "Sony Microsystems", "group":1}, 64 | { "name": "Stellar Computer", "group":1}, 65 | { "name": "Stratus", "group":1}, 66 | { "name": "Sumitronics", "group":1}, 67 | { "name": "Sun Microsystems", "group":7}, 68 | { "name": "Televideo", "group":7}, 69 | { "name": "Texas Instruments","group":7}, 70 | { "name": "Whitechapel Workstations", "group":7}, 71 | { "name": "Xerox", "group":7}, 72 | { "name": "AEG", "group":7}, 73 | { "name": "Calcomp", "group":1}, 74 | { "name": "UNISYS", "group":1}, 75 | { "name": "Valid Logic Systems", "group":1}, 76 | { "name": "Tektronix", "group":1}, 77 | { "name": "Adage Inc.", "group":1}, 78 | ], 79 | "links": [ 80 | { "source": 1, "target": 7, "value": 1}, 81 | { "source": 1, "target": 30, "value": 1}, 82 | { "source": 1, "target": 31, "value": 2}, 83 | { "source": 1, "target": 44, "value": 1}, 84 | { "source": 1, "target": 62, "value": 1}, 85 | { "source": 1, "target": 64, "value": 1}, 86 | { "source": 1, "target": 66, "value": 1}, 87 | {"source": 3, "target": 3, "value": 4}, 88 | {"source": 3, "target": 4, "value": 1}, 89 | {"source": 3, "target": 5, "value": 1}, 90 | {"source": 3, "target": 7, "value": 1}, 91 | {"source": 3, "target": 8, "value": 2}, 92 | {"source": 3, "target": 10, "value": 2}, 93 | {"source": 3, "target": 21, "value": 1}, 94 | {"source": 3, "target": 26, "value": 1}, 95 | {"source": 3, "target": 28, "value": 1}, 96 | {"source": 3, "target": 31, "value": 4}, 97 | {"source": 3, "target": 32, "value": 1}, 98 | {"source": 3, "target": 35, "value": 1}, 99 | {"source": 3, "target": 36, "value": 2}, 100 | {"source": 3, "target": 39, "value": 1}, 101 | {"source": 3, "target": 41, "value": 1}, 102 | {"source": 3, "target": 43, "value": 1}, 103 | {"source": 3, "target": 44, "value": 1}, 104 | {"source": 3, "target": 48, "value": 1}, 105 | {"source": 3, "target": 50, "value": 2}, 106 | {"source": 3, "target": 62, "value": 1}, 107 | {"source": 4, "target": 3, "value": 1}, 108 | {"source": 4, "target": 4, "value": 17}, 109 | {"source": 4, "target": 5, "value": 17}, 110 | {"source": 4, "target": 7, "value": 3}, 111 | {"source": 4, "target": 8, "value": 5}, 112 | {"source": 4, "target": 10, "value": 1}, 113 | {"source": 4, "target": 11, "value": 2}, 114 | {"source": 4, "target": 21, "value": 1}, 115 | {"source": 4, "target": 26, "value": 2}, 116 | {"source": 4, "target": 28, "value": 4}, 117 | {"source": 4, "target": 29, "value": 2}, 118 | {"source": 4, "target": 30, "value": 4}, 119 | {"source": 4, "target": 31, "value": 11}, 120 | {"source": 4, "target": 32, "value": 2}, 121 | {"source": 4, "target": 35, "value": 1}, 122 | {"source": 4, "target": 36, "value": 2}, 123 | {"source": 4, "target": 39, "value": 1}, 124 | {"source": 4, "target": 41, "value": 1}, 125 | {"source": 4, "target": 42, "value": 1}, 126 | {"source": 4, "target": 43, "value": 4}, 127 | {"source": 4, "target": 44, "value": 3}, 128 | {"source": 4, "target": 45, "value": 1}, 129 | {"source": 4, "target": 48, "value": 1}, 130 | {"source": 4, "target": 50, "value": 2}, 131 | {"source": 4, "target": 56, "value": 1}, 132 | {"source": 4, "target": 57, "value": 3}, 133 | {"source": 4, "target": 60, "value": 1}, 134 | {"source": 4, "target": 62, "value": 5}, 135 | {"source": 4, "target": 63, "value": 1}, 136 | {"source": 4, "target": 64, "value": 2}, 137 | {"source": 5, "target": 3, "value": 1}, 138 | {"source": 5, "target": 4, "value": 17}, 139 | {"source": 5, "target": 5, "value": 17}, 140 | {"source": 5, "target": 7, "value": 3}, 141 | {"source": 5, "target": 8, "value": 5}, 142 | {"source": 5, "target": 10, "value": 1}, 143 | {"source": 5, "target": 11, "value": 2}, 144 | {"source": 5, "target": 21, "value": 1}, 145 | {"source": 5, "target": 26, "value": 2}, 146 | {"source": 5, "target": 28, "value": 4}, 147 | {"source": 5, "target": 29, "value": 2}, 148 | {"source": 5, "target": 30, "value": 4}, 149 | {"source": 5, "target": 31, "value": 11}, 150 | {"source": 5, "target": 32, "value": 2}, 151 | {"source": 5, "target": 35, "value": 1}, 152 | {"source": 5, "target": 36, "value": 2}, 153 | {"source": 5, "target": 39, "value": 1}, 154 | {"source": 5, "target": 41, "value": 1}, 155 | {"source": 5, "target": 42, "value": 1}, 156 | {"source": 5, "target": 43, "value": 4}, 157 | {"source": 5, "target": 44, "value": 3}, 158 | {"source": 5, "target": 45, "value": 1}, 159 | {"source": 5, "target": 48, "value": 1}, 160 | {"source": 5, "target": 50, "value": 2}, 161 | {"source": 5, "target": 56, "value": 1}, 162 | {"source": 5, "target": 57, "value": 3}, 163 | {"source": 5, "target": 60, "value": 1}, 164 | {"source": 5, "target": 62, "value": 5}, 165 | {"source": 5, "target": 63, "value": 1}, 166 | {"source": 5, "target": 64, "value": 2}, 167 | {"source": 7, "target": 1, "value": 1}, 168 | {"source": 7, "target": 3, "value": 1}, 169 | {"source": 7, "target": 4, "value": 3}, 170 | {"source": 7, "target": 5, "value": 3}, 171 | {"source": 7, "target": 7, "value": 138}, 172 | {"source": 7, "target": 8, "value": 14}, 173 | {"source": 7, "target": 9, "value": 20}, 174 | {"source": 7, "target": 10, "value": 2}, 175 | {"source": 7, "target": 11, "value": 1}, 176 | {"source": 7, "target": 12, "value": 3}, 177 | {"source": 7, "target": 21, "value": 5}, 178 | {"source": 7, "target": 22, "value": 12}, 179 | {"source": 7, "target": 25, "value": 1}, 180 | {"source": 7, "target": 26, "value": 8}, 181 | {"source": 7, "target": 28, "value": 42}, 182 | {"source": 7, "target": 29, "value": 1}, 183 | {"source": 7, "target": 30, "value": 18}, 184 | {"source": 7, "target": 31, "value": 72}, 185 | {"source": 7, "target": 32, "value": 9}, 186 | {"source": 7, "target": 35, "value": 2}, 187 | {"source": 7, "target": 36, "value": 3}, 188 | {"source": 7, "target": 39, "value": 2}, 189 | {"source": 7, "target": 41, "value": 2}, 190 | {"source": 7, "target": 43, "value": 4}, 191 | {"source": 7, "target": 44, "value": 6}, 192 | {"source": 7, "target": 45, "value": 1}, 193 | {"source": 7, "target": 48, "value": 1}, 194 | {"source": 7, "target": 50, "value": 2}, 195 | {"source": 7, "target": 56, "value": 2}, 196 | {"source": 7, "target": 57, "value": 19}, 197 | {"source": 7, "target": 58, "value": 3}, 198 | {"source": 7, "target": 59, "value": 19}, 199 | {"source": 7, "target": 60, "value": 4}, 200 | {"source": 7, "target": 62, "value": 66}, 201 | {"source": 7, "target": 64, "value": 6}, 202 | {"source": 7, "target": 66, "value": 6}, 203 | {"source": 7, "target": 68, "value": 1}, 204 | {"source": 7, "target": 69, "value": 1}, 205 | {"source": 7, "target": 70, "value": 2}, 206 | {"source": 7, "target": 71, "value": 14}, 207 | {"source": 8, "target": 3, "value": 2}, 208 | {"source": 8, "target": 4, "value": 5}, 209 | {"source": 8, "target": 5, "value": 5}, 210 | {"source": 8, "target": 7, "value": 14}, 211 | {"source": 8, "target": 8, "value": 121}, 212 | {"source": 8, "target": 9, "value": 1}, 213 | {"source": 8, "target": 10, "value": 1}, 214 | {"source": 8, "target": 11, "value": 4}, 215 | {"source": 8, "target": 12, "value": 3}, 216 | {"source": 8, "target": 13, "value": 1}, 217 | {"source": 8, "target": 20, "value": 1}, 218 | {"source": 8, "target": 21, "value": 2}, 219 | {"source": 8, "target": 22, "value": 2}, 220 | {"source": 8, "target": 26, "value": 3}, 221 | {"source": 8, "target": 28, "value": 38}, 222 | {"source": 8, "target": 30, "value": 8}, 223 | {"source": 8, "target": 31, "value": 76}, 224 | {"source": 8, "target": 32, "value": 4}, 225 | {"source": 8, "target": 35, "value": 1}, 226 | {"source": 8, "target": 36, "value": 7}, 227 | {"source": 8, "target": 39, "value": 1}, 228 | {"source": 8, "target": 41, "value": 1}, 229 | {"source": 8, "target": 43, "value": 4}, 230 | {"source": 8, "target": 44, "value": 2}, 231 | {"source": 8, "target": 48, "value": 1}, 232 | {"source": 8, "target": 50, "value": 4}, 233 | {"source": 8, "target": 56, "value": 1}, 234 | {"source": 8, "target": 57, "value": 6}, 235 | {"source": 8, "target": 58, "value": 2}, 236 | {"source": 8, "target": 59, "value": 2}, 237 | {"source": 8, "target": 60, "value": 1}, 238 | {"source": 8, "target": 62, "value": 38}, 239 | {"source": 8, "target": 63, "value": 2}, 240 | {"source": 8, "target": 64, "value": 13}, 241 | {"source": 8, "target": 66, "value": 10}, 242 | {"source": 8, "target": 68, "value": 2}, 243 | {"source": 8, "target": 69, "value": 1}, 244 | {"source": 8, "target": 71, "value": 6}, 245 | {"source": 9, "target": 7, "value": 20}, 246 | {"source": 9, "target": 8, "value": 1}, 247 | {"source": 9, "target": 9, "value": 23}, 248 | {"source": 9, "target": 12, "value": 2}, 249 | {"source": 9, "target": 14, "value": 1}, 250 | {"source": 9, "target": 21, "value": 5}, 251 | {"source": 9, "target": 22, "value": 7}, 252 | {"source": 9, "target": 28, "value": 1}, 253 | {"source": 9, "target": 30, "value": 1}, 254 | {"source": 9, "target": 31, "value": 3}, 255 | {"source": 9, "target": 32, "value": 1}, 256 | {"source": 9, "target": 39, "value": 1}, 257 | {"source": 9, "target": 52, "value": 1}, 258 | {"source": 9, "target": 57, "value": 11}, 259 | {"source": 9, "target": 59, "value": 17}, 260 | {"source": 9, "target": 62, "value": 13}, 261 | {"source": 9, "target": 64, "value": 1}, 262 | {"source": 9, "target": 65, "value": 1}, 263 | {"source": 9, "target": 66, "value": 1}, 264 | {"source": 10, "target": 3, "value": 2}, 265 | {"source": 10, "target": 4, "value": 1}, 266 | {"source": 10, "target": 5, "value": 1}, 267 | {"source": 10, "target": 7, "value": 2}, 268 | {"source": 10, "target": 8, "value": 1}, 269 | {"source": 10, "target": 10, "value": 5}, 270 | {"source": 10, "target": 21, "value": 1}, 271 | {"source": 10, "target": 26, "value": 1}, 272 | {"source": 10, "target": 28, "value": 1}, 273 | {"source": 10, "target": 31, "value": 4}, 274 | {"source": 10, "target": 32, "value": 1}, 275 | {"source": 10, "target": 35, "value": 1}, 276 | {"source": 10, "target": 36, "value": 2}, 277 | {"source": 10, "target": 39, "value": 1}, 278 | {"source": 10, "target": 41, "value": 1}, 279 | {"source": 10, "target": 43, "value": 1}, 280 | {"source": 10, "target": 44, "value": 1}, 281 | {"source": 10, "target": 48, "value": 1}, 282 | {"source": 10, "target": 50, "value": 2}, 283 | {"source": 10, "target": 62, "value": 3}, 284 | {"source": 10, "target": 66, "value": 1}, 285 | {"source": 11, "target": 4, "value": 2}, 286 | {"source": 11, "target": 5, "value": 2}, 287 | {"source": 11, "target": 7, "value": 1}, 288 | {"source": 11, "target": 8, "value": 4}, 289 | {"source": 11, "target": 11, "value": 10}, 290 | {"source": 11, "target": 28, "value": 2}, 291 | {"source": 11, "target": 29, "value": 1}, 292 | {"source": 11, "target": 30, "value": 1}, 293 | {"source": 11, "target": 31, "value": 9}, 294 | {"source": 11, "target": 32, "value": 1}, 295 | {"source": 11, "target": 56, "value": 1}, 296 | {"source": 11, "target": 60, "value": 1}, 297 | {"source": 11, "target": 64, "value": 1}, 298 | {"source": 12, "target": 7, "value": 3}, 299 | {"source": 12, "target": 8, "value": 3}, 300 | {"source": 12, "target": 9, "value": 2}, 301 | {"source": 12, "target": 12, "value": 11}, 302 | {"source": 12, "target": 26, "value": 1}, 303 | {"source": 12, "target": 28, "value": 2}, 304 | {"source": 12, "target": 30, "value": 1}, 305 | {"source": 12, "target": 31, "value": 6}, 306 | {"source": 12, "target": 32, "value": 1}, 307 | {"source": 12, "target": 43, "value": 1}, 308 | {"source": 12, "target": 44, "value": 1}, 309 | {"source": 12, "target": 57, "value": 2}, 310 | {"source": 12, "target": 62, "value": 3}, 311 | {"source": 12, "target": 66, "value": 1}, 312 | {"source": 12, "target": 71, "value": 1}, 313 | {"source": 13, "target": 8, "value": 1}, 314 | {"source": 13, "target": 13, "value": 3}, 315 | {"source": 13, "target": 26, "value": 1}, 316 | {"source": 13, "target": 28, "value": 1}, 317 | {"source": 13, "target": 30, "value": 1}, 318 | {"source": 13, "target": 31, "value": 2}, 319 | {"source": 13, "target": 36, "value": 1}, 320 | {"source": 13, "target": 44, "value": 1}, 321 | {"source": 14, "target": 9, "value": 1}, 322 | {"source": 14, "target": 14, "value": 3}, 323 | {"source": 14, "target": 15, "value": 1}, 324 | {"source": 14, "target": 25, "value": 1}, 325 | {"source": 14, "target": 39, "value": 1}, 326 | {"source": 14, "target": 52, "value": 1}, 327 | {"source": 14, "target": 57, "value": 1}, 328 | {"source": 14, "target": 65, "value": 1}, 329 | {"source": 15, "target": 14, "value": 1}, 330 | {"source": 15, "target": 15, "value": 3}, 331 | {"source": 15, "target": 25, "value": 1}, 332 | {"source": 15, "target": 31, "value": 1}, 333 | {"source": 20, "target": 8, "value": 1}, 334 | {"source": 20, "target": 20, "value": 4}, 335 | {"source": 20, "target": 28, "value": 1}, 336 | {"source": 20, "target": 31, "value": 1}, 337 | {"source": 20, "target": 36, "value": 1}, 338 | {"source": 20, "target": 57, "value": 1}, 339 | {"source": 21, "target": 3, "value": 1}, 340 | {"source": 21, "target": 4, "value": 1}, 341 | {"source": 21, "target": 5, "value": 1}, 342 | {"source": 21, "target": 7, "value": 5}, 343 | {"source": 21, "target": 8, "value": 2}, 344 | {"source": 21, "target": 9, "value": 5}, 345 | {"source": 21, "target": 10, "value": 1}, 346 | {"source": 21, "target": 21, "value": 11}, 347 | {"source": 21, "target": 22, "value": 2}, 348 | {"source": 21, "target": 26, "value": 1}, 349 | {"source": 21, "target": 28, "value": 2}, 350 | {"source": 21, "target": 31, "value": 5}, 351 | {"source": 21, "target": 32, "value": 2}, 352 | {"source": 21, "target": 35, "value": 1}, 353 | {"source": 21, "target": 36, "value": 1}, 354 | {"source": 21, "target": 39, "value": 1}, 355 | {"source": 21, "target": 41, "value": 1}, 356 | {"source": 21, "target": 43, "value": 2}, 357 | {"source": 21, "target": 44, "value": 1}, 358 | {"source": 21, "target": 48, "value": 1}, 359 | {"source": 21, "target": 50, "value": 1}, 360 | {"source": 21, "target": 57, "value": 3}, 361 | {"source": 21, "target": 59, "value": 4}, 362 | {"source": 21, "target": 62, "value": 3}, 363 | {"source": 21, "target": 64, "value": 1}, 364 | {"source": 21, "target": 66, "value": 1}, 365 | {"source": 22, "target": 7, "value": 12}, 366 | {"source": 22, "target": 8, "value": 2}, 367 | {"source": 22, "target": 9, "value": 7}, 368 | {"source": 22, "target": 21, "value": 2}, 369 | {"source": 22, "target": 22, "value": 13}, 370 | {"source": 22, "target": 26, "value": 2}, 371 | {"source": 22, "target": 28, "value": 2}, 372 | {"source": 22, "target": 30, "value": 1}, 373 | {"source": 22, "target": 31, "value": 4}, 374 | {"source": 22, "target": 32, "value": 1}, 375 | {"source": 22, "target": 36, "value": 1}, 376 | {"source": 22, "target": 41, "value": 1}, 377 | {"source": 22, "target": 57, "value": 3}, 378 | {"source": 22, "target": 59, "value": 6}, 379 | {"source": 22, "target": 62, "value": 4}, 380 | {"source": 22, "target": 66, "value": 1}, 381 | {"source": 22, "target": 71, "value": 1}, 382 | {"source": 23, "target": 23, "value": 2}, 383 | {"source": 23, "target": 28, "value": 1}, 384 | {"source": 23, "target": 31, "value": 1}, 385 | {"source": 23, "target": 36, "value": 1}, 386 | {"source": 24, "target": 24, "value": 1}, 387 | {"source": 24, "target": 31, "value": 1}, 388 | {"source": 25, "target": 7, "value": 1}, 389 | {"source": 25, "target": 14, "value": 1}, 390 | {"source": 25, "target": 15, "value": 1}, 391 | {"source": 25, "target": 25, "value": 6}, 392 | {"source": 25, "target": 31, "value": 1}, 393 | {"source": 25, "target": 62, "value": 3}, 394 | {"source": 26, "target": 3, "value": 1}, 395 | {"source": 26, "target": 4, "value": 2}, 396 | {"source": 26, "target": 5, "value": 2}, 397 | {"source": 26, "target": 7, "value": 8}, 398 | {"source": 26, "target": 8, "value": 3}, 399 | {"source": 26, "target": 10, "value": 1}, 400 | {"source": 26, "target": 12, "value": 1}, 401 | {"source": 26, "target": 13, "value": 1}, 402 | {"source": 26, "target": 21, "value": 1}, 403 | {"source": 26, "target": 22, "value": 2}, 404 | {"source": 26, "target": 26, "value": 30}, 405 | {"source": 26, "target": 28, "value": 12}, 406 | {"source": 26, "target": 30, "value": 5}, 407 | {"source": 26, "target": 31, "value": 26}, 408 | {"source": 26, "target": 32, "value": 1}, 409 | {"source": 26, "target": 35, "value": 1}, 410 | {"source": 26, "target": 36, "value": 3}, 411 | {"source": 26, "target": 39, "value": 1}, 412 | {"source": 26, "target": 41, "value": 2}, 413 | {"source": 26, "target": 42, "value": 2}, 414 | {"source": 26, "target": 43, "value": 3}, 415 | {"source": 26, "target": 44, "value": 3}, 416 | {"source": 26, "target": 45, "value": 1}, 417 | {"source": 26, "target": 48, "value": 1}, 418 | {"source": 26, "target": 50, "value": 1}, 419 | {"source": 26, "target": 60, "value": 1}, 420 | {"source": 26, "target": 62, "value": 5}, 421 | {"source": 26, "target": 64, "value": 1}, 422 | {"source": 26, "target": 66, "value": 4}, 423 | {"source": 26, "target": 71, "value": 1}, 424 | {"source": 28, "target": 3, "value": 1}, 425 | {"source": 28, "target": 4, "value": 4}, 426 | {"source": 28, "target": 5, "value": 4}, 427 | {"source": 28, "target": 7, "value": 42}, 428 | {"source": 28, "target": 8, "value": 38}, 429 | {"source": 28, "target": 9, "value": 1}, 430 | {"source": 28, "target": 10, "value": 1}, 431 | {"source": 28, "target": 11, "value": 2}, 432 | {"source": 28, "target": 12, "value": 2}, 433 | {"source": 28, "target": 13, "value": 1}, 434 | {"source": 28, "target": 20, "value": 1}, 435 | {"source": 28, "target": 21, "value": 2}, 436 | {"source": 28, "target": 22, "value": 2}, 437 | {"source": 28, "target": 23, "value": 1}, 438 | {"source": 28, "target": 26, "value": 12}, 439 | {"source": 28, "target": 28, "value": 178}, 440 | {"source": 28, "target": 29, "value": 2}, 441 | {"source": 28, "target": 30, "value": 20}, 442 | {"source": 28, "target": 31, "value": 132}, 443 | {"source": 28, "target": 32, "value": 6}, 444 | {"source": 28, "target": 35, "value": 1}, 445 | {"source": 28, "target": 36, "value": 8}, 446 | {"source": 28, "target": 38, "value": 1}, 447 | {"source": 28, "target": 39, "value": 1}, 448 | {"source": 28, "target": 41, "value": 1}, 449 | {"source": 28, "target": 42, "value": 2}, 450 | {"source": 28, "target": 43, "value": 6}, 451 | {"source": 28, "target": 44, "value": 8}, 452 | {"source": 28, "target": 45, "value": 2}, 453 | {"source": 28, "target": 50, "value": 1}, 454 | {"source": 28, "target": 57, "value": 8}, 455 | {"source": 28, "target": 58, "value": 1}, 456 | {"source": 28, "target": 59, "value": 3}, 457 | {"source": 28, "target": 60, "value": 4}, 458 | {"source": 28, "target": 62, "value": 46}, 459 | {"source": 28, "target": 63, "value": 1}, 460 | {"source": 28, "target": 64, "value": 5}, 461 | {"source": 28, "target": 66, "value": 9}, 462 | {"source": 28, "target": 69, "value": 2}, 463 | {"source": 28, "target": 70, "value": 2}, 464 | {"source": 28, "target": 71, "value": 10}, 465 | {"source": 29, "target": 4, "value": 2}, 466 | {"source": 29, "target": 5, "value": 2}, 467 | {"source": 29, "target": 7, "value": 1}, 468 | {"source": 29, "target": 11, "value": 1}, 469 | {"source": 29, "target": 28, "value": 2}, 470 | {"source": 29, "target": 29, "value": 9}, 471 | {"source": 29, "target": 30, "value": 1}, 472 | {"source": 29, "target": 31, "value": 5}, 473 | {"source": 29, "target": 32, "value": 2}, 474 | {"source": 29, "target": 36, "value": 1}, 475 | {"source": 29, "target": 43, "value": 1}, 476 | {"source": 29, "target": 56, "value": 1}, 477 | {"source": 29, "target": 60, "value": 1}, 478 | {"source": 29, "target": 62, "value": 1}, 479 | {"source": 29, "target": 63, "value": 1}, 480 | {"source": 29, "target": 64, "value": 3}, 481 | {"source": 29, "target": 66, "value": 1}, 482 | {"source": 30, "target": 1, "value": 1}, 483 | {"source": 30, "target": 4, "value": 4}, 484 | {"source": 30, "target": 5, "value": 4}, 485 | {"source": 30, "target": 7, "value": 18}, 486 | {"source": 30, "target": 8, "value": 8}, 487 | {"source": 30, "target": 9, "value": 1}, 488 | {"source": 30, "target": 11, "value": 1}, 489 | {"source": 30, "target": 12, "value": 1}, 490 | {"source": 30, "target": 13, "value": 1}, 491 | {"source": 30, "target": 22, "value": 1}, 492 | {"source": 30, "target": 26, "value": 5}, 493 | {"source": 30, "target": 28, "value": 20}, 494 | {"source": 30, "target": 29, "value": 1}, 495 | {"source": 30, "target": 30, "value": 65}, 496 | {"source": 30, "target": 31, "value": 44}, 497 | {"source": 30, "target": 32, "value": 4}, 498 | {"source": 30, "target": 36, "value": 5}, 499 | {"source": 30, "target": 39, "value": 1}, 500 | {"source": 30, "target": 42, "value": 1}, 501 | {"source": 30, "target": 43, "value": 4}, 502 | {"source": 30, "target": 44, "value": 1}, 503 | {"source": 30, "target": 45, "value": 3}, 504 | {"source": 30, "target": 50, "value": 2}, 505 | {"source": 30, "target": 57, "value": 6}, 506 | {"source": 30, "target": 58, "value": 2}, 507 | {"source": 30, "target": 59, "value": 3}, 508 | {"source": 30, "target": 60, "value": 3}, 509 | {"source": 30, "target": 62, "value": 15}, 510 | {"source": 30, "target": 64, "value": 4}, 511 | {"source": 30, "target": 66, "value": 4}, 512 | {"source": 30, "target": 68, "value": 3}, 513 | {"source": 30, "target": 69, "value": 1}, 514 | {"source": 30, "target": 71, "value": 5}, 515 | {"source": 31, "target": 1, "value": 2}, 516 | {"source": 31, "target": 3, "value": 4}, 517 | {"source": 31, "target": 4, "value": 11}, 518 | {"source": 31, "target": 5, "value": 11}, 519 | {"source": 31, "target": 7, "value": 72}, 520 | {"source": 31, "target": 8, "value": 76}, 521 | {"source": 31, "target": 9, "value": 3}, 522 | {"source": 31, "target": 10, "value": 4}, 523 | {"source": 31, "target": 11, "value": 9}, 524 | {"source": 31, "target": 12, "value": 6}, 525 | {"source": 31, "target": 13, "value": 2}, 526 | {"source": 31, "target": 15, "value": 1}, 527 | {"source": 31, "target": 20, "value": 1}, 528 | {"source": 31, "target": 21, "value": 5}, 529 | {"source": 31, "target": 22, "value": 4}, 530 | {"source": 31, "target": 23, "value": 1}, 531 | {"source": 31, "target": 24, "value": 1}, 532 | {"source": 31, "target": 25, "value": 1}, 533 | {"source": 31, "target": 26, "value": 26}, 534 | {"source": 31, "target": 28, "value": 132}, 535 | {"source": 31, "target": 29, "value": 5}, 536 | {"source": 31, "target": 30, "value": 44}, 537 | {"source": 31, "target": 31, "value": 541}, 538 | {"source": 31, "target": 32, "value": 13}, 539 | {"source": 31, "target": 35, "value": 2}, 540 | {"source": 31, "target": 36, "value": 16}, 541 | {"source": 31, "target": 38, "value": 2}, 542 | {"source": 31, "target": 39, "value": 2}, 543 | {"source": 31, "target": 41, "value": 1}, 544 | {"source": 31, "target": 42, "value": 4}, 545 | {"source": 31, "target": 43, "value": 19}, 546 | {"source": 31, "target": 44, "value": 20}, 547 | {"source": 31, "target": 45, "value": 3}, 548 | {"source": 31, "target": 48, "value": 1}, 549 | {"source": 31, "target": 50, "value": 7}, 550 | {"source": 31, "target": 56, "value": 2}, 551 | {"source": 31, "target": 57, "value": 16}, 552 | {"source": 31, "target": 58, "value": 1}, 553 | {"source": 31, "target": 59, "value": 5}, 554 | {"source": 31, "target": 60, "value": 6}, 555 | {"source": 31, "target": 62, "value": 106}, 556 | {"source": 31, "target": 63, "value": 2}, 557 | {"source": 31, "target": 64, "value": 16}, 558 | {"source": 31, "target": 66, "value": 24}, 559 | {"source": 31, "target": 68, "value": 7}, 560 | {"source": 31, "target": 69, "value": 6}, 561 | {"source": 31, "target": 71, "value": 20}, 562 | {"source": 32, "target": 3, "value": 1}, 563 | {"source": 32, "target": 4, "value": 2}, 564 | {"source": 32, "target": 5, "value": 2}, 565 | {"source": 32, "target": 7, "value": 9}, 566 | {"source": 32, "target": 8, "value": 4}, 567 | {"source": 32, "target": 9, "value": 1}, 568 | {"source": 32, "target": 10, "value": 1}, 569 | {"source": 32, "target": 11, "value": 1}, 570 | {"source": 32, "target": 12, "value": 1}, 571 | {"source": 32, "target": 21, "value": 2}, 572 | {"source": 32, "target": 22, "value": 1}, 573 | {"source": 32, "target": 26, "value": 1}, 574 | {"source": 32, "target": 28, "value": 6}, 575 | {"source": 32, "target": 29, "value": 2}, 576 | {"source": 32, "target": 30, "value": 4}, 577 | {"source": 32, "target": 31, "value": 13}, 578 | {"source": 32, "target": 32, "value": 19}, 579 | {"source": 32, "target": 35, "value": 1}, 580 | {"source": 32, "target": 36, "value": 1}, 581 | {"source": 32, "target": 39, "value": 2}, 582 | {"source": 32, "target": 41, "value": 1}, 583 | {"source": 32, "target": 43, "value": 2}, 584 | {"source": 32, "target": 44, "value": 1}, 585 | {"source": 32, "target": 48, "value": 1}, 586 | {"source": 32, "target": 50, "value": 1}, 587 | {"source": 32, "target": 56, "value": 1}, 588 | {"source": 32, "target": 57, "value": 3}, 589 | {"source": 32, "target": 58, "value": 1}, 590 | {"source": 32, "target": 59, "value": 3}, 591 | {"source": 32, "target": 60, "value": 1}, 592 | {"source": 32, "target": 62, "value": 7}, 593 | {"source": 32, "target": 64, "value": 1}, 594 | {"source": 32, "target": 66, "value": 1}, 595 | {"source": 32, "target": 71, "value": 2}, 596 | {"source": 35, "target": 3, "value": 1}, 597 | {"source": 35, "target": 4, "value": 1}, 598 | {"source": 35, "target": 5, "value": 1}, 599 | {"source": 35, "target": 7, "value": 2}, 600 | {"source": 35, "target": 8, "value": 1}, 601 | {"source": 35, "target": 10, "value": 1}, 602 | {"source": 35, "target": 21, "value": 1}, 603 | {"source": 35, "target": 26, "value": 1}, 604 | {"source": 35, "target": 28, "value": 1}, 605 | {"source": 35, "target": 31, "value": 2}, 606 | {"source": 35, "target": 32, "value": 1}, 607 | {"source": 35, "target": 35, "value": 2}, 608 | {"source": 35, "target": 36, "value": 1}, 609 | {"source": 35, "target": 39, "value": 1}, 610 | {"source": 35, "target": 41, "value": 1}, 611 | {"source": 35, "target": 43, "value": 1}, 612 | {"source": 35, "target": 44, "value": 1}, 613 | {"source": 35, "target": 48, "value": 1}, 614 | {"source": 35, "target": 50, "value": 1}, 615 | {"source": 35, "target": 62, "value": 1}, 616 | {"source": 36, "target": 3, "value": 2}, 617 | {"source": 36, "target": 4, "value": 2}, 618 | {"source": 36, "target": 5, "value": 2}, 619 | {"source": 36, "target": 7, "value": 3}, 620 | {"source": 36, "target": 8, "value": 7}, 621 | {"source": 36, "target": 10, "value": 2}, 622 | {"source": 36, "target": 13, "value": 1}, 623 | {"source": 36, "target": 20, "value": 1}, 624 | {"source": 36, "target": 21, "value": 1}, 625 | {"source": 36, "target": 22, "value": 1}, 626 | {"source": 36, "target": 23, "value": 1}, 627 | {"source": 36, "target": 26, "value": 3}, 628 | {"source": 36, "target": 28, "value": 8}, 629 | {"source": 36, "target": 29, "value": 1}, 630 | {"source": 36, "target": 30, "value": 5}, 631 | {"source": 36, "target": 31, "value": 16}, 632 | {"source": 36, "target": 32, "value": 1}, 633 | {"source": 36, "target": 35, "value": 1}, 634 | {"source": 36, "target": 36, "value": 19}, 635 | {"source": 36, "target": 39, "value": 1}, 636 | {"source": 36, "target": 41, "value": 1}, 637 | {"source": 36, "target": 42, "value": 1}, 638 | {"source": 36, "target": 43, "value": 3}, 639 | {"source": 36, "target": 44, "value": 2}, 640 | {"source": 36, "target": 45, "value": 2}, 641 | {"source": 36, "target": 48, "value": 1}, 642 | {"source": 36, "target": 50, "value": 2}, 643 | {"source": 36, "target": 56, "value": 1}, 644 | {"source": 36, "target": 57, "value": 1}, 645 | {"source": 36, "target": 62, "value": 3}, 646 | {"source": 36, "target": 64, "value": 1}, 647 | {"source": 36, "target": 66, "value": 3}, 648 | {"source": 36, "target": 69, "value": 1}, 649 | {"source": 36, "target": 71, "value": 6}, 650 | {"source": 37, "target": 37, "value": 1}, 651 | {"source": 37, "target": 62, "value": 1}, 652 | {"source": 38, "target": 28, "value": 1}, 653 | {"source": 38, "target": 31, "value": 2}, 654 | {"source": 38, "target": 38, "value": 2}, 655 | {"source": 39, "target": 3, "value": 1}, 656 | {"source": 39, "target": 4, "value": 1}, 657 | {"source": 39, "target": 5, "value": 1}, 658 | {"source": 39, "target": 7, "value": 2}, 659 | {"source": 39, "target": 8, "value": 1}, 660 | {"source": 39, "target": 9, "value": 1}, 661 | {"source": 39, "target": 10, "value": 1}, 662 | {"source": 39, "target": 14, "value": 1}, 663 | {"source": 39, "target": 21, "value": 1}, 664 | {"source": 39, "target": 26, "value": 1}, 665 | {"source": 39, "target": 28, "value": 1}, 666 | {"source": 39, "target": 30, "value": 1}, 667 | {"source": 39, "target": 31, "value": 2}, 668 | {"source": 39, "target": 32, "value": 2}, 669 | {"source": 39, "target": 35, "value": 1}, 670 | {"source": 39, "target": 36, "value": 1}, 671 | {"source": 39, "target": 39, "value": 3}, 672 | {"source": 39, "target": 41, "value": 1}, 673 | {"source": 39, "target": 43, "value": 1}, 674 | {"source": 39, "target": 44, "value": 1}, 675 | {"source": 39, "target": 48, "value": 1}, 676 | {"source": 39, "target": 50, "value": 1}, 677 | {"source": 39, "target": 52, "value": 1}, 678 | {"source": 39, "target": 57, "value": 2}, 679 | {"source": 39, "target": 59, "value": 1}, 680 | {"source": 39, "target": 62, "value": 2}, 681 | {"source": 39, "target": 65, "value": 1}, 682 | {"source": 39, "target": 71, "value": 1}, 683 | {"source": 41, "target": 3, "value": 1}, 684 | {"source": 41, "target": 4, "value": 1}, 685 | {"source": 41, "target": 5, "value": 1}, 686 | {"source": 41, "target": 7, "value": 2}, 687 | {"source": 41, "target": 8, "value": 1}, 688 | {"source": 41, "target": 10, "value": 1}, 689 | {"source": 41, "target": 21, "value": 1}, 690 | {"source": 41, "target": 22, "value": 1}, 691 | {"source": 41, "target": 26, "value": 2}, 692 | {"source": 41, "target": 28, "value": 1}, 693 | {"source": 41, "target": 31, "value": 1}, 694 | {"source": 41, "target": 32, "value": 1}, 695 | {"source": 41, "target": 35, "value": 1}, 696 | {"source": 41, "target": 36, "value": 1}, 697 | {"source": 41, "target": 39, "value": 1}, 698 | {"source": 41, "target": 41, "value": 2}, 699 | {"source": 41, "target": 43, "value": 1}, 700 | {"source": 41, "target": 44, "value": 1}, 701 | {"source": 41, "target": 48, "value": 1}, 702 | {"source": 41, "target": 50, "value": 1}, 703 | {"source": 41, "target": 62, "value": 1}, 704 | {"source": 42, "target": 4, "value": 1}, 705 | {"source": 42, "target": 5, "value": 1}, 706 | {"source": 42, "target": 26, "value": 2}, 707 | {"source": 42, "target": 28, "value": 2}, 708 | {"source": 42, "target": 30, "value": 1}, 709 | {"source": 42, "target": 31, "value": 4}, 710 | {"source": 42, "target": 36, "value": 1}, 711 | {"source": 42, "target": 42, "value": 7}, 712 | {"source": 42, "target": 64, "value": 1}, 713 | {"source": 43, "target": 3, "value": 1}, 714 | {"source": 43, "target": 4, "value": 4}, 715 | {"source": 43, "target": 5, "value": 4}, 716 | {"source": 43, "target": 7, "value": 4}, 717 | {"source": 43, "target": 8, "value": 4}, 718 | {"source": 43, "target": 10, "value": 1}, 719 | {"source": 43, "target": 12, "value": 1}, 720 | {"source": 43, "target": 21, "value": 2}, 721 | {"source": 43, "target": 26, "value": 3}, 722 | {"source": 43, "target": 28, "value": 6}, 723 | {"source": 43, "target": 29, "value": 1}, 724 | {"source": 43, "target": 30, "value": 4}, 725 | {"source": 43, "target": 31, "value": 19}, 726 | {"source": 43, "target": 32, "value": 2}, 727 | {"source": 43, "target": 35, "value": 1}, 728 | {"source": 43, "target": 36, "value": 3}, 729 | {"source": 43, "target": 39, "value": 1}, 730 | {"source": 43, "target": 41, "value": 1}, 731 | {"source": 43, "target": 43, "value": 28}, 732 | {"source": 43, "target": 44, "value": 2}, 733 | {"source": 43, "target": 45, "value": 3}, 734 | {"source": 43, "target": 48, "value": 1}, 735 | {"source": 43, "target": 50, "value": 2}, 736 | {"source": 43, "target": 60, "value": 1}, 737 | {"source": 43, "target": 62, "value": 8}, 738 | {"source": 43, "target": 63, "value": 1}, 739 | {"source": 43, "target": 66, "value": 1}, 740 | {"source": 43, "target": 68, "value": 1}, 741 | {"source": 43, "target": 69, "value": 2}, 742 | {"source": 43, "target": 71, "value": 1}, 743 | {"source": 44, "target": 1, "value": 1}, 744 | {"source": 44, "target": 3, "value": 1}, 745 | {"source": 44, "target": 4, "value": 3}, 746 | {"source": 44, "target": 5, "value": 3}, 747 | {"source": 44, "target": 7, "value": 6}, 748 | {"source": 44, "target": 8, "value": 2}, 749 | {"source": 44, "target": 10, "value": 1}, 750 | {"source": 44, "target": 12, "value": 1}, 751 | {"source": 44, "target": 13, "value": 1}, 752 | {"source": 44, "target": 21, "value": 1}, 753 | {"source": 44, "target": 26, "value": 3}, 754 | {"source": 44, "target": 28, "value": 8}, 755 | {"source": 44, "target": 30, "value": 1}, 756 | {"source": 44, "target": 31, "value": 20}, 757 | {"source": 44, "target": 32, "value": 1}, 758 | {"source": 44, "target": 35, "value": 1}, 759 | {"source": 44, "target": 36, "value": 2}, 760 | {"source": 44, "target": 39, "value": 1}, 761 | {"source": 44, "target": 41, "value": 1}, 762 | {"source": 44, "target": 43, "value": 2}, 763 | {"source": 44, "target": 44, "value": 26}, 764 | {"source": 44, "target": 48, "value": 1}, 765 | {"source": 44, "target": 50, "value": 1}, 766 | {"source": 44, "target": 60, "value": 1}, 767 | {"source": 44, "target": 62, "value": 6}, 768 | {"source": 44, "target": 64, "value": 2}, 769 | {"source": 44, "target": 66, "value": 4}, 770 | {"source": 44, "target": 71, "value": 1}, 771 | {"source": 45, "target": 4, "value": 1}, 772 | {"source": 45, "target": 5, "value": 1}, 773 | {"source": 45, "target": 7, "value": 1}, 774 | {"source": 45, "target": 26, "value": 1}, 775 | {"source": 45, "target": 28, "value": 2}, 776 | {"source": 45, "target": 30, "value": 3}, 777 | {"source": 45, "target": 31, "value": 3}, 778 | {"source": 45, "target": 36, "value": 2}, 779 | {"source": 45, "target": 43, "value": 3}, 780 | {"source": 45, "target": 45, "value": 4}, 781 | {"source": 45, "target": 50, "value": 1}, 782 | {"source": 45, "target": 62, "value": 3}, 783 | {"source": 48, "target": 3, "value": 1}, 784 | {"source": 48, "target": 4, "value": 1}, 785 | {"source": 48, "target": 5, "value": 1}, 786 | {"source": 48, "target": 7, "value": 1}, 787 | {"source": 48, "target": 8, "value": 1}, 788 | {"source": 48, "target": 10, "value": 1}, 789 | {"source": 48, "target": 21, "value": 1}, 790 | {"source": 48, "target": 26, "value": 1}, 791 | {"source": 48, "target": 31, "value": 1}, 792 | {"source": 48, "target": 32, "value": 1}, 793 | {"source": 48, "target": 35, "value": 1}, 794 | {"source": 48, "target": 36, "value": 1}, 795 | {"source": 48, "target": 39, "value": 1}, 796 | {"source": 48, "target": 41, "value": 1}, 797 | {"source": 48, "target": 43, "value": 1}, 798 | {"source": 48, "target": 44, "value": 1}, 799 | {"source": 48, "target": 48, "value": 1}, 800 | {"source": 48, "target": 50, "value": 1}, 801 | {"source": 48, "target": 62, "value": 1}, 802 | {"source": 50, "target": 3, "value": 2}, 803 | {"source": 50, "target": 4, "value": 2}, 804 | {"source": 50, "target": 5, "value": 2}, 805 | {"source": 50, "target": 7, "value": 2}, 806 | {"source": 50, "target": 8, "value": 4}, 807 | {"source": 50, "target": 10, "value": 2}, 808 | {"source": 50, "target": 21, "value": 1}, 809 | {"source": 50, "target": 26, "value": 1}, 810 | {"source": 50, "target": 28, "value": 1}, 811 | {"source": 50, "target": 30, "value": 2}, 812 | {"source": 50, "target": 31, "value": 7}, 813 | {"source": 50, "target": 32, "value": 1}, 814 | {"source": 50, "target": 35, "value": 1}, 815 | {"source": 50, "target": 36, "value": 2}, 816 | {"source": 50, "target": 39, "value": 1}, 817 | {"source": 50, "target": 41, "value": 1}, 818 | {"source": 50, "target": 43, "value": 2}, 819 | {"source": 50, "target": 44, "value": 1}, 820 | {"source": 50, "target": 45, "value": 1}, 821 | {"source": 50, "target": 48, "value": 1}, 822 | {"source": 50, "target": 50, "value": 8}, 823 | {"source": 50, "target": 62, "value": 5}, 824 | {"source": 50, "target": 63, "value": 2}, 825 | {"source": 50, "target": 69, "value": 1}, 826 | {"source": 51, "target": 51, "value": 2}, 827 | {"source": 51, "target": 62, "value": 2}, 828 | {"source": 52, "target": 9, "value": 1}, 829 | {"source": 52, "target": 14, "value": 1}, 830 | {"source": 52, "target": 39, "value": 1}, 831 | {"source": 52, "target": 52, "value": 1}, 832 | {"source": 52, "target": 57, "value": 1}, 833 | {"source": 52, "target": 65, "value": 1}, 834 | {"source": 55, "target": 55, "value": 1}, 835 | {"source": 56, "target": 4, "value": 1}, 836 | {"source": 56, "target": 5, "value": 1}, 837 | {"source": 56, "target": 7, "value": 2}, 838 | {"source": 56, "target": 8, "value": 1}, 839 | {"source": 56, "target": 11, "value": 1}, 840 | {"source": 56, "target": 29, "value": 1}, 841 | {"source": 56, "target": 31, "value": 2}, 842 | {"source": 56, "target": 32, "value": 1}, 843 | {"source": 56, "target": 36, "value": 1}, 844 | {"source": 56, "target": 56, "value": 2}, 845 | {"source": 56, "target": 60, "value": 1}, 846 | {"source": 56, "target": 62, "value": 1}, 847 | {"source": 56, "target": 64, "value": 1}, 848 | {"source": 56, "target": 66, "value": 1}, 849 | {"source": 56, "target": 71, "value": 1}, 850 | {"source": 57, "target": 4, "value": 3}, 851 | {"source": 57, "target": 5, "value": 3}, 852 | {"source": 57, "target": 7, "value": 19}, 853 | {"source": 57, "target": 8, "value": 6}, 854 | {"source": 57, "target": 9, "value": 11}, 855 | {"source": 57, "target": 12, "value": 2}, 856 | {"source": 57, "target": 14, "value": 1}, 857 | {"source": 57, "target": 20, "value": 1}, 858 | {"source": 57, "target": 21, "value": 3}, 859 | {"source": 57, "target": 22, "value": 3}, 860 | {"source": 57, "target": 28, "value": 8}, 861 | {"source": 57, "target": 30, "value": 6}, 862 | {"source": 57, "target": 31, "value": 16}, 863 | {"source": 57, "target": 32, "value": 3}, 864 | {"source": 57, "target": 36, "value": 1}, 865 | {"source": 57, "target": 39, "value": 2}, 866 | {"source": 57, "target": 52, "value": 1}, 867 | {"source": 57, "target": 57, "value": 39}, 868 | {"source": 57, "target": 59, "value": 9}, 869 | {"source": 57, "target": 62, "value": 20}, 870 | {"source": 57, "target": 64, "value": 1}, 871 | {"source": 57, "target": 65, "value": 1}, 872 | {"source": 57, "target": 66, "value": 1}, 873 | {"source": 57, "target": 71, "value": 4}, 874 | {"source": 58, "target": 7, "value": 3}, 875 | {"source": 58, "target": 8, "value": 2}, 876 | {"source": 58, "target": 28, "value": 1}, 877 | {"source": 58, "target": 30, "value": 2}, 878 | {"source": 58, "target": 31, "value": 1}, 879 | {"source": 58, "target": 32, "value": 1}, 880 | {"source": 58, "target": 58, "value": 7}, 881 | {"source": 58, "target": 59, "value": 1}, 882 | {"source": 58, "target": 62, "value": 3}, 883 | {"source": 59, "target": 7, "value": 19}, 884 | {"source": 59, "target": 8, "value": 2}, 885 | {"source": 59, "target": 9, "value": 17}, 886 | {"source": 59, "target": 21, "value": 4}, 887 | {"source": 59, "target": 22, "value": 6}, 888 | {"source": 59, "target": 28, "value": 3}, 889 | {"source": 59, "target": 30, "value": 3}, 890 | {"source": 59, "target": 31, "value": 5}, 891 | {"source": 59, "target": 32, "value": 3}, 892 | {"source": 59, "target": 39, "value": 1}, 893 | {"source": 59, "target": 57, "value": 9}, 894 | {"source": 59, "target": 58, "value": 1}, 895 | {"source": 59, "target": 59, "value": 21}, 896 | {"source": 59, "target": 62, "value": 13}, 897 | {"source": 59, "target": 64, "value": 1}, 898 | {"source": 59, "target": 71, "value": 1}, 899 | {"source": 60, "target": 4, "value": 1}, 900 | {"source": 60, "target": 5, "value": 1}, 901 | {"source": 60, "target": 7, "value": 4}, 902 | {"source": 60, "target": 8, "value": 1}, 903 | {"source": 60, "target": 11, "value": 1}, 904 | {"source": 60, "target": 26, "value": 1}, 905 | {"source": 60, "target": 28, "value": 4}, 906 | {"source": 60, "target": 29, "value": 1}, 907 | {"source": 60, "target": 30, "value": 3}, 908 | {"source": 60, "target": 31, "value": 6}, 909 | {"source": 60, "target": 32, "value": 1}, 910 | {"source": 60, "target": 43, "value": 1}, 911 | {"source": 60, "target": 44, "value": 1}, 912 | {"source": 60, "target": 56, "value": 1}, 913 | {"source": 60, "target": 60, "value": 9}, 914 | {"source": 60, "target": 62, "value": 3}, 915 | {"source": 60, "target": 64, "value": 1}, 916 | {"source": 60, "target": 69, "value": 1}, 917 | {"source": 62, "target": 1, "value": 1}, 918 | {"source": 62, "target": 3, "value": 1}, 919 | {"source": 62, "target": 4, "value": 5}, 920 | {"source": 62, "target": 5, "value": 5}, 921 | {"source": 62, "target": 7, "value": 66}, 922 | {"source": 62, "target": 8, "value": 38}, 923 | {"source": 62, "target": 9, "value": 13}, 924 | {"source": 62, "target": 10, "value": 3}, 925 | {"source": 62, "target": 12, "value": 3}, 926 | {"source": 62, "target": 21, "value": 3}, 927 | {"source": 62, "target": 22, "value": 4}, 928 | {"source": 62, "target": 25, "value": 3}, 929 | {"source": 62, "target": 26, "value": 5}, 930 | {"source": 62, "target": 28, "value": 46}, 931 | {"source": 62, "target": 29, "value": 1}, 932 | {"source": 62, "target": 30, "value": 15}, 933 | {"source": 62, "target": 31, "value": 106}, 934 | {"source": 62, "target": 32, "value": 7}, 935 | {"source": 62, "target": 35, "value": 1}, 936 | {"source": 62, "target": 36, "value": 3}, 937 | {"source": 62, "target": 37, "value": 1}, 938 | {"source": 62, "target": 39, "value": 2}, 939 | {"source": 62, "target": 41, "value": 1}, 940 | {"source": 62, "target": 43, "value": 8}, 941 | {"source": 62, "target": 44, "value": 6}, 942 | {"source": 62, "target": 45, "value": 3}, 943 | {"source": 62, "target": 48, "value": 1}, 944 | {"source": 62, "target": 50, "value": 5}, 945 | {"source": 62, "target": 51, "value": 2}, 946 | {"source": 62, "target": 56, "value": 1}, 947 | {"source": 62, "target": 57, "value": 20}, 948 | {"source": 62, "target": 58, "value": 3}, 949 | {"source": 62, "target": 59, "value": 13}, 950 | {"source": 62, "target": 60, "value": 3}, 951 | {"source": 62, "target": 62, "value": 214}, 952 | {"source": 62, "target": 64, "value": 4}, 953 | {"source": 62, "target": 66, "value": 9}, 954 | {"source": 62, "target": 68, "value": 1}, 955 | {"source": 62, "target": 69, "value": 4}, 956 | {"source": 62, "target": 70, "value": 4}, 957 | {"source": 62, "target": 71, "value": 10}, 958 | {"source": 63, "target": 4, "value": 1}, 959 | {"source": 63, "target": 5, "value": 1}, 960 | {"source": 63, "target": 8, "value": 2}, 961 | {"source": 63, "target": 28, "value": 1}, 962 | {"source": 63, "target": 29, "value": 1}, 963 | {"source": 63, "target": 31, "value": 2}, 964 | {"source": 63, "target": 43, "value": 1}, 965 | {"source": 63, "target": 50, "value": 2}, 966 | {"source": 63, "target": 63, "value": 5}, 967 | {"source": 64, "target": 1, "value": 1}, 968 | {"source": 64, "target": 4, "value": 2}, 969 | {"source": 64, "target": 5, "value": 2}, 970 | {"source": 64, "target": 7, "value": 6}, 971 | {"source": 64, "target": 8, "value": 13}, 972 | {"source": 64, "target": 9, "value": 1}, 973 | {"source": 64, "target": 11, "value": 1}, 974 | {"source": 64, "target": 21, "value": 1}, 975 | {"source": 64, "target": 26, "value": 1}, 976 | {"source": 64, "target": 28, "value": 5}, 977 | {"source": 64, "target": 29, "value": 3}, 978 | {"source": 64, "target": 30, "value": 4}, 979 | {"source": 64, "target": 31, "value": 16}, 980 | {"source": 64, "target": 32, "value": 1}, 981 | {"source": 64, "target": 36, "value": 1}, 982 | {"source": 64, "target": 42, "value": 1}, 983 | {"source": 64, "target": 44, "value": 2}, 984 | {"source": 64, "target": 56, "value": 1}, 985 | {"source": 64, "target": 57, "value": 1}, 986 | {"source": 64, "target": 59, "value": 1}, 987 | {"source": 64, "target": 60, "value": 1}, 988 | {"source": 64, "target": 62, "value": 4}, 989 | {"source": 64, "target": 64, "value": 32}, 990 | {"source": 64, "target": 66, "value": 2}, 991 | {"source": 64, "target": 68, "value": 1}, 992 | {"source": 64, "target": 71, "value": 1}, 993 | {"source": 65, "target": 9, "value": 1}, 994 | {"source": 65, "target": 14, "value": 1}, 995 | {"source": 65, "target": 39, "value": 1}, 996 | {"source": 65, "target": 52, "value": 1}, 997 | {"source": 65, "target": 57, "value": 1}, 998 | {"source": 65, "target": 65, "value": 1}, 999 | {"source": 66, "target": 1, "value": 1}, 1000 | {"source": 66, "target": 7, "value": 6}, 1001 | {"source": 66, "target": 8, "value": 10}, 1002 | {"source": 66, "target": 9, "value": 1}, 1003 | {"source": 66, "target": 10, "value": 1}, 1004 | {"source": 66, "target": 12, "value": 1}, 1005 | {"source": 66, "target": 21, "value": 1}, 1006 | {"source": 66, "target": 22, "value": 1}, 1007 | {"source": 66, "target": 26, "value": 4}, 1008 | {"source": 66, "target": 28, "value": 9}, 1009 | {"source": 66, "target": 29, "value": 1}, 1010 | {"source": 66, "target": 30, "value": 4}, 1011 | {"source": 66, "target": 31, "value": 24}, 1012 | {"source": 66, "target": 32, "value": 1}, 1013 | {"source": 66, "target": 36, "value": 3}, 1014 | {"source": 66, "target": 43, "value": 1}, 1015 | {"source": 66, "target": 44, "value": 4}, 1016 | {"source": 66, "target": 56, "value": 1}, 1017 | {"source": 66, "target": 57, "value": 1}, 1018 | {"source": 66, "target": 62, "value": 9}, 1019 | {"source": 66, "target": 64, "value": 2}, 1020 | {"source": 66, "target": 66, "value": 50}, 1021 | {"source": 66, "target": 68, "value": 2}, 1022 | {"source": 66, "target": 70, "value": 1}, 1023 | {"source": 66, "target": 71, "value": 4}, 1024 | {"source": 68, "target": 7, "value": 1}, 1025 | {"source": 68, "target": 8, "value": 2}, 1026 | {"source": 68, "target": 30, "value": 3}, 1027 | {"source": 68, "target": 31, "value": 7}, 1028 | {"source": 68, "target": 43, "value": 1}, 1029 | {"source": 68, "target": 62, "value": 1}, 1030 | {"source": 68, "target": 64, "value": 1}, 1031 | {"source": 68, "target": 66, "value": 2}, 1032 | {"source": 68, "target": 68, "value": 8}, 1033 | {"source": 69, "target": 7, "value": 1}, 1034 | {"source": 69, "target": 8, "value": 1}, 1035 | {"source": 69, "target": 28, "value": 2}, 1036 | {"source": 69, "target": 30, "value": 1}, 1037 | {"source": 69, "target": 31, "value": 6}, 1038 | {"source": 69, "target": 36, "value": 1}, 1039 | {"source": 69, "target": 43, "value": 2}, 1040 | {"source": 69, "target": 50, "value": 1}, 1041 | {"source": 69, "target": 60, "value": 1}, 1042 | {"source": 69, "target": 62, "value": 4}, 1043 | {"source": 69, "target": 69, "value": 9}, 1044 | {"source": 70, "target": 7, "value": 2}, 1045 | {"source": 70, "target": 28, "value": 2}, 1046 | {"source": 70, "target": 62, "value": 4}, 1047 | {"source": 70, "target": 66, "value": 1}, 1048 | {"source": 70, "target": 70, "value": 7}, 1049 | {"source": 70, "target": 71, "value": 2}, 1050 | {"source": 71, "target": 7, "value": 14}, 1051 | {"source": 71, "target": 8, "value": 6}, 1052 | {"source": 71, "target": 12, "value": 1}, 1053 | {"source": 71, "target": 22, "value": 1}, 1054 | {"source": 71, "target": 26, "value": 1}, 1055 | {"source": 71, "target": 28, "value": 10}, 1056 | {"source": 71, "target": 30, "value": 5}, 1057 | {"source": 71, "target": 31, "value": 20}, 1058 | {"source": 71, "target": 32, "value": 2}, 1059 | {"source": 71, "target": 36, "value": 6}, 1060 | {"source": 71, "target": 39, "value": 1}, 1061 | {"source": 71, "target": 43, "value": 1}, 1062 | {"source": 71, "target": 44, "value": 1}, 1063 | {"source": 71, "target": 56, "value": 1}, 1064 | {"source": 71, "target": 57, "value": 4}, 1065 | {"source": 71, "target": 59, "value": 1}, 1066 | {"source": 71, "target": 62, "value": 10}, 1067 | {"source": 71, "target": 64, "value": 1}, 1068 | {"source": 71, "target": 66, "value": 4}, 1069 | {"source": 71, "target": 70, "value": 2}, 1070 | {"source": 71, "target": 71, "value": 35}, 1071 | {"source": 72, "target": 72, "value": 1} 1072 | ] 1073 | }; 1074 | 1075 | --------------------------------------------------------------------------------