├── .gitignore ├── .watchr ├── CONTRIBUTORS ├── Gruntfile.js ├── LICENSE ├── README.md ├── build ├── 0.5.0 │ ├── openspending.css │ ├── openspending.js │ ├── openspending.min.css │ └── openspending.min.js └── 0.5.1 │ ├── openspending.css │ ├── openspending.js │ ├── openspending.min.css │ └── openspending.min.js ├── demo ├── README.md ├── bubbletree.png ├── bubbletree │ ├── by-cofog1-then-cofog2.csv │ └── index.html ├── timeseries.png ├── timeseries │ ├── by-year-then-cofog1-then-department.csv │ └── index.html ├── treemap.png └── treemap │ ├── by-cofog1-then-department.csv │ └── index.html ├── karma.conf.js ├── lib ├── .gitignore └── vendor │ ├── Tween.js │ ├── accounting.js │ ├── bubbletree │ └── 2.0 │ │ ├── bubbletree.cofog.js │ │ ├── bubbletree.js │ │ ├── bubbletree.min.js │ │ └── bubbletree.openspending.js │ ├── chroma.js │ ├── csv.js │ ├── d3.v3.min.js │ ├── jquery.history.js │ ├── jquery.qtip.min.js │ ├── kartograph │ └── kartograph.min.js │ ├── raphael-min.js │ ├── thejit-2.js │ ├── underscore.js │ └── vis4.js ├── package.json ├── publish_assets.sh ├── releases ├── openspendingjs-0.1.0.tgz ├── openspendingjs-0.1.0.zip ├── openspendingjs-0.2.0.tgz ├── openspendingjs-0.2.0.zip ├── openspendingjs-0.2.1.tgz ├── openspendingjs-0.2.1.zip ├── openspendingjs-0.3.0.tgz ├── openspendingjs-0.3.0.zip ├── openspendingjs-0.4.0.tgz └── openspendingjs-0.4.0.zip ├── src ├── css │ ├── bubbletree.css │ ├── dailybread.css │ ├── linebars.css │ ├── stackedbar.css │ ├── tooltips.css │ └── treemap.css ├── svg │ ├── EC.svg │ ├── admin-culture.svg │ ├── admin-order-safety.svg │ ├── admin.svg │ ├── africa.svg │ ├── aid-developing-countries.svg │ ├── aid.svg │ ├── airplane.svg │ ├── ambulance.svg │ ├── anchor.svg │ ├── asia.svg │ ├── books.svg │ ├── car.svg │ ├── civil-defence.svg │ ├── coal.svg │ ├── communication.svg │ ├── community.svg │ ├── construction.svg │ ├── courts.svg │ ├── culture.svg │ ├── defence-admin.svg │ ├── defence-research.svg │ ├── defence.svg │ ├── dental.svg │ ├── dollar.svg │ ├── economic-aid.svg │ ├── education.svg │ ├── electricity.svg │ ├── energy.svg │ ├── energy2.svg │ ├── environment-admin.svg │ ├── environment.svg │ ├── euro.svg │ ├── family.svg │ ├── family2.svg │ ├── farms.svg │ ├── financial-admin.svg │ ├── fire-brigade.svg │ ├── fishing.svg │ ├── foreign-military-aid.svg │ ├── forest.svg │ ├── fuel.svg │ ├── government-uk.svg │ ├── health.svg │ ├── helping-others.svg │ ├── hospital-specialized.svg │ ├── hospital.svg │ ├── housing.svg │ ├── human-resources.svg │ ├── island.svg │ ├── labour.svg │ ├── legislative.svg │ ├── manufactoring-construction.svg │ ├── media.svg │ ├── medical-supplies.svg │ ├── microscope.svg │ ├── military.svg │ ├── misc-services.svg │ ├── money.svg │ ├── nuclear.svg │ ├── old-age.svg │ ├── order-safety.svg │ ├── other-medical.svg │ ├── our-streets.svg │ ├── petrol.svg │ ├── pig.svg │ ├── planning.svg │ ├── police.svg │ ├── police2.svg │ ├── pollution.svg │ ├── post-secondary.svg │ ├── pound.svg │ ├── pound2.svg │ ├── pre-school.svg │ ├── primary.svg │ ├── prisons.svg │ ├── public-debt.svg │ ├── railways.svg │ ├── rd-order-safety.svg │ ├── research.svg │ ├── satellite-dish.svg │ ├── schools.svg │ ├── secondary-lower.svg │ ├── secondary-upper.svg │ ├── social-systems.svg │ ├── sports.svg │ ├── street-lights.svg │ ├── toilet.svg │ ├── transport.svg │ ├── tree.svg │ ├── unemployment.svg │ ├── unknown.svg │ ├── waste.svg │ ├── water.svg │ ├── wheelchair.svg │ ├── wind.svg │ └── worldmap.svg ├── utils │ ├── README.md │ ├── openspending.aggregator.js │ ├── openspending.amounts.js │ ├── openspending.bubble.js │ ├── openspending.colors.js │ ├── openspending.common.js │ ├── openspending.csvloader.js │ ├── openspending.icons.js │ └── openspending.taxman.js └── visualisations │ ├── README.md │ ├── jquery.barchart.js │ ├── jquery.bubbletree.js │ ├── jquery.choropleth.js │ ├── jquery.dailybread.js │ ├── jquery.linebars.js │ ├── jquery.stackedbar.js │ └── jquery.treemap.js └── tests ├── fixtures.js ├── index.html ├── linebars.html ├── spec └── lib │ ├── aggregator.coffee │ ├── boot.coffee │ ├── datastore.coffee │ ├── main.coffee │ ├── model.coffee │ ├── utils │ ├── gdocs.coffee │ ├── tree.coffee │ └── utils.coffee │ └── widgets.coffee ├── stackedbar.html └── vendor ├── coffee-script.js └── sinon.js /.gitignore: -------------------------------------------------------------------------------- 1 | .redo 2 | ## general 3 | *.orig 4 | *~ 5 | .DS_Store 6 | .*.swp 7 | sandbox/* 8 | ## specific 9 | scripts/localconfig.js 10 | src/flash-ordnance 11 | src/dfid 12 | src/flash-working 13 | /node_modules 14 | -------------------------------------------------------------------------------- /.watchr: -------------------------------------------------------------------------------- 1 | watch ( 'app/(.*)\.coffee' ) { |md| system("./build.sh; ") } 2 | watch ( 'app/(.*)\.js' ) { |md| system("./build.sh; ") } 3 | watch ( 'widgets/(.*)\.js' ) { |md| system("./build.sh; ") } 4 | watch ( 'lib/(.*)\.js' ) { |md| system("./build.sh; ") } 5 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | Contributors to Openspendingjs in alphabetical order (by last name or nick): 4 | 5 | * Gregor Aisch 6 | * AnnaPS 7 | * Nigel Babu 8 | * Vitor Baptista 9 | * Michael Bauer 10 | * Tryggvi Bjorgvinsson 11 | * James Casbon 12 | * Tim Hubbard 13 | * Martin Keegan 14 | * Friedrich Lindenberg 15 | * Rufus Pollock 16 | * Carsten Senger 17 | * Nick Stenning 18 | * Andrew Suffield 19 | * Stefan Wehrmeyer 20 | * Mila Frerichs 21 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | concat: { 6 | js: { 7 | options: { 8 | separator: ';' 9 | }, 10 | src: [ 11 | // Add requirements manually so unused can be removed later 12 | 'lib/vendor/raphael-min.js', 13 | 'lib/vendor/chroma.js', 14 | 'lib/vendor/kartograph/kartograph.min.js', 15 | 'lib/vendor/underscore.js', 16 | 'lib/vendor/accounting.js', 17 | 'lib/vendor/thejit-2.js', 18 | 'lib/vendor/d3.v3.js', 19 | 'lib/vendor/vis4.js', 20 | 'lib/vendor/jquery.history.js', 21 | 'lib/vendor/Tween.js', 22 | 'lib/vendor/bubbletree/2.0/bubbletree.openspending.js', 23 | 'lib/vendor/jquery.qtip.min.js', 24 | 'lib/vendor/csv.js', 25 | // Source files for openspendingjs' utilisation library 26 | 'src/utils/*.js', 27 | // Source files for openspendingjs' jquery widgets 28 | 'src/visualisations/*.js' 29 | ], 30 | dest: 'build/<%= pkg.version %>/<%= pkg.shortname %>.js' 31 | }, 32 | css: { 33 | src: ['src/css/*.css'], 34 | dest: 'build/<%= pkg.version %>/<%= pkg.shortname %>.css' 35 | } 36 | }, 37 | min: { 38 | options: { 39 | report: grunt.option('report') ? 'gzip' : false 40 | }, 41 | js: { 42 | src: ['<%= concat.js.dest %>'], 43 | dest: 'build/<%= pkg.version %>/<%= pkg.shortname %>.min.js' 44 | } 45 | }, 46 | cssmin : { 47 | options: { 48 | report: grunt.option('report') ? 'gzip' : false 49 | }, 50 | css: { 51 | src: ['<%= concat.css.dest %>'], 52 | dest: 'build/<%= pkg.version %>/<%= pkg.shortname %>.min.css' 53 | } 54 | }, 55 | copy: { 56 | svg: { 57 | files: [ 58 | { expand: true, src: ['svg/**.svg'], 59 | cwd: 'src/', 60 | dest: 'build/<%= pkg.version %>/icons/' } 61 | ] 62 | } 63 | }, 64 | compress: { 65 | tarball: { 66 | options: { 67 | archive: 'releases/<%= pkg.name %>-<%= pkg.version %>.tgz', 68 | }, 69 | expand: true, 70 | src: ['<%= pkg.version %>/**'], 71 | cwd: 'build/', 72 | dest: '<%= pkg.name %>' 73 | }, 74 | zipfile: { 75 | options: { 76 | archive: 'releases/<%= pkg.name %>-<%= pkg.version %>.zip', 77 | }, 78 | expand: true, 79 | src: ['<%= pkg.version %>/**'], 80 | cwd: 'build/', 81 | dest: '<%= pkg.name %>' 82 | } 83 | }, 84 | clean: ["build/"], 85 | karma: { 86 | options: { 87 | configFile: 'karma.conf.js', 88 | }, 89 | unit: { 90 | } 91 | } 92 | }); 93 | 94 | grunt.loadNpmTasks('grunt-contrib-concat'); 95 | grunt.loadNpmTasks('grunt-yui-compressor'); 96 | grunt.loadNpmTasks('grunt-contrib-copy'); 97 | grunt.loadNpmTasks('grunt-contrib-compress'); 98 | grunt.loadNpmTasks('grunt-contrib-clean'); 99 | grunt.loadNpmTasks('grunt-karma'); 100 | 101 | grunt.registerTask('default', ['concat', 'min', 'cssmin', 'copy']); 102 | grunt.registerTask('release', ['concat', 'min', 'cssmin', 103 | 'copy', 'compress', 'clean']); 104 | }; 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenSpending Javascript libraries 2 | 3 | Visualisations and other utils that use data from [OpenSpending](http://openspending.org) to help people understand where and how money is being spent. 4 | 5 | ## Want to Use Openspendingjs? 6 | 7 | Just drop the most recent file in *dist/* into your website (via a script tag) and start using the visualisations. You can read more about configurations for the different visualisations in *src/README.md* 8 | 9 | ## Want to Contribute to Openspendingjs? 10 | 11 | We are currently in a migration stage in order to make contributions easier and more consistent, so the code base might be a little confusing. The best place to add your visualisation is *src/*. We're in the process of moving all of our visualisations and utils into that folder (to make the build process cleaner and simpler). 12 | 13 | External libraries (requirements) are placed in *lib/vendor/*. There are a lot of files there at the moment. Some of those files are old versions of these libraries. We're in the process of cleaning these files up, removing unused files. 14 | 15 | ### Conventions 16 | 17 | There are some conventions regarding the javascript files in the *src* directory to keep them consistent. 18 | 19 | #### jQuery Plugins 20 | 21 | All of the visualisations should be constructed as [jQuery](http://jquery.com) plugins which make them really easy to use. jQuery is already used on a lot of sites ([OpenSpending](http://openspending.org) included), so this really makes it simple to use openspendingjs on many sites. 22 | 23 | If you want them to be usable as plugins for other javascript frameworks (or as a standalone library), don't be afraid to contribute to openspendingjs. 24 | 25 | #### Comment, Comment, Comment 26 | 27 | Sometimes comments can be in the way but rarely they don't. Try to comment your code as much as possible. *Sherlock-commenting* (where code reader goes: *"No shit, Sherlock!"*) is better than no commenting at all. 28 | 29 | Openspendingjs is not only a usable library but it can also help new developers become more proficient in development, and encourages them to contribute to openspendingjs! 30 | 31 | #### Declare License in Source Files 32 | 33 | Openspendingjs is licensed under the Apache License, version 2.0. Each source file should include the Apache license notice. We recommend you assign the copyright to the [Open Knowledge Foundation ](http://okfn.org) in the notice. The Open Knowledge Foundation will take utmost care to enforce the license conditions. Please help us track violation to the license. 34 | 35 | #### Add Your Name to the Contributors List 36 | 37 | We try to keep a list of contributors to openspendingjs in *CONTRIBUTORS*. It is extremely important that you get credit for your work even if the Open Knowledge Foundation is the custodian of the copyright as per the license. We value all contributions (so the list of contributors is in alphabetical order). 38 | 39 | #### List Requirements in Source Files 40 | 41 | Openspendingjs doesn't use any module loaders or other means of managing requirements but listing them in a comment helps maintainers who want to upgrade libraries to find affected files (we don't have a good test framework in place at the moment so upgrading libraries should be done with care). 42 | 43 | #### List Requirements Individually in Build File 44 | 45 | To make the clean up process simpler, when you add external libraries to the build process, list the individual files in the build file (*Gruntfile.js*). This also shows developers what will already be concatenated into the openspendingjs distribution file (since our *lib/vendor* directory might be slightly confusing). 46 | 47 | ## Build process 48 | 49 | To build openspendingjs we use [Grunt](http://gruntjs.com/) version *>= 0.4* which requires [Node.js](http://nodejs.org) version *>= 0.8*. The build process is simple: 50 | 51 | grunt 52 | 53 | If you want to see the different sizes of the files you can use the *report* option: 54 | 55 | grunt --report 56 | 57 | This compiles all source files and their requirements (yes we add all libraries, watch out for conflicts) into two files in *dist/*: 58 | 59 | * /openspending.js (where version is openspendingjs version number) 60 | * /openspending.min.js (minified version of the above file) 61 | 62 | The version number in package.json should of course be update for new releases. 63 | 64 | The build process does the same for all css stylesheets (creates openspending.css and openspending.min.css) and copies all svg files into a subfolder of called icons. 65 | 66 | The files are placed in a build folder. 67 | 68 | To build a release you can runt: 69 | 70 | grunt release 71 | 72 | This cleans (removes) the build folder after creating both a tgz and a zip file for the version containing the built files. 73 | 74 | ### Testing 75 | 76 | If you want to run the tests use karma with grunt: 77 | 78 | grunt karma 79 | 80 | ### Don't Have Such a Recent Node.js Version? 81 | 82 | When developing it's good to set up virtual environments to manage dependencies instead of installing them into your system (and therefore possibly breaking other projects you're working on). 83 | 84 | One way to create a virtual environment for Node.js is to use [nodeenv](https://github.com/ekalinin/nodeenv). It can be installed in a python environment (using python's [virtualenv](http://www.virtualenv.org/)). 85 | -------------------------------------------------------------------------------- /build/0.5.0/openspending.min.css: -------------------------------------------------------------------------------- 1 | .openspending-bt{position:relative;overflow:hidden}.openspending-bt .label{position:absolute;color:#fff;text-align:center;cursor:default}.openspending-bt .amount{font-family:Georgia,sans-serif;font-size:16px}.openspending-bt .desc{font-family:sans-serif;font-size:11px}.openspending-bt .label2{position:absolute;color:#000;text-align:center;cursor:default;font-size:11px;font-family:sans-serif;margin-top:5px}.openspending-bt .label2 span{background:#fff}.loading{z-index:1000;position:absolute;width:700px;height:400px}.openspending-bt-wrapper .tooltip{max-width:220px;border:1px solid #999;position:absolute;background:#fff;z-index:9999;box-shadow:3px 3px 0 rgba(0,0,0,.2);border-radius:2px;font-family:sans-serif;font-size:13px;padding:4px}.openspending-bt-wrapper .tooltip .header{padding:6px}.openspending-bt-wrapper .tooltip .header .icon{width:38px;height:38px;float:left;background:#600;border-radius:19px;margin-right:8px}.openspending-bt .tooltip svg{width:100px;height:100px;fill:black;display:block;position:relative;visibility:visible;z-index:10000}.openspending-bt .tooltip svg path{fill-opacity:1;visiblity:visible}.openspending-bt-wrapper .tooltip .row{clear:both;border-top:1px solid #999;padding:6px}#tooltip{position:absolute;z-index:3000;background-color:#fff;padding:5px;border:1px solid #999;box-shadow:3px 3px 0 rgba(0,0,0,.2);border-radius:2px;font-family:sans-serif;font-size:13px;padding:4px;max-width:200px}#tooltip .amount{font-weight:bold}#tooltip h3,#tooltip div{margin:0}p#vtip #vtipArrow{position:absolute;top:-10px;left:5px}.slice{display:inline-block;text-align:center}.controls{vertical-align:top}.salary,.tax{width:15%;display:inline-block}.salary{text-align:left}.tax{text-align:right}.salary p,.tax p{color:#830242;font-size:1.2em;font-weight:bold;text-transform:uppercase}.indirects{margin:15px 0}.indirects label{color:#830242;font-size:1.2em}.indirects label input[type='checkbox']{display:inline-block;margin-right:2px}.slider{display:inline-block;text-align:center;width:70%}.slider .ui-widget-content{background:0;background-color:#830242;height:6px}.slider .ui-slider-horizontal .ui-slider-handle{background:url('../img/currency-slider.png') transparent no-repeat;height:34px;width:32px;border:0;cursor:move;margin-top:-0.4em;margin-left:-0.8em}.slider div#ticks{font-size:90%;margin-top:5px}.slider div.tick-min{float:left;margin-left:-5px}.slider div.tick-max{float:right;margin-right:-15px}path.bar{fill:#ccc}path.topline{fill:none;stroke-width:1.5px;stroke:#333}g.bar{opacity:.5}g.bar:hover,g.selected{opacity:1}text.dotlabel{opacity:0;font-size:60%}g.bar:hover text.dotlabel,g.selected text.dotlabel{opacity:1}text.yearlabel{font-size:70%}g.axis path,g.axis line{fill:none;stroke:#aaa}g.axis text{font-size:70%;fill:#aaa}.bar rect{fill:#000;stroke:#FFF;stroke-width:1px;opacity:.5}.bar:hover rect{opacity:.7}ul.sb-breadcrumbs{padding:0;margin:0}ul.sb-breadcrumbs li{display:inline;margin-right:10px}ul.sb-breadcrunmbs li:hover{text-decoration:underline}svg body{margin:0}ul.sb-breadcrumbs li:before{color:#ccc;content:">"}.ui-tooltip-content .amount{font-size:20px;font-weight:normal;font-family:Palatino,Georgia;border-top:1px dashed #ccc;padding-top:8px;margin:5px 0 3px}.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:180px;min-width:50px;font-size:12px;line-height:15px;z-index:15000}.ui-tooltip-fluid{display:block;visibility:hidden;position:static !important;float:left !important}.ui-tooltip-content{position:relative;padding:5px 9px;overflow:hidden;border-width:1px;border-style:solid;text-align:left;word-wrap:break-word;overflow:hidden}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border-width:1px 1px 0;border-style:solid;font-weight:bold}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0 !important}/*! Default close button class */.ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid}* html .ui-tooltip-titlebar .ui-state-default{top:16px}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}/*! Default tooltip style */.ui-tooltip-default .ui-tooltip-titlebar,.ui-tooltip-default .ui-tooltip-content{border-color:#777;background-color:#fff;color:#000;border-radius:0 0 5px 5px;box-shadow:3px 3px 5px rgba(0,0,0,.3)}.ui-tooltip-default .ui-tooltip-titlebar{background-color:#222;color:#fff;border-radius:5px 5px 0 0;font-size:12px;font-weight:300;font-family:"OpenSansLight","Helvetica Neue",Helvetica,Arial,sans-serif}.ui-tooltip-default .ui-tooltip-icon{border-color:#CCC;background:#f1f1f1;color:#777}.ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111}.treemap-widget{position:relative;overflow:hidden;cursor:pointer;height:100%;color:#fff;font-family:Share;font-size:.8em;font-weight:bold}.treemap-widget div.desc{padding:.8em;font-weight:normal;overflow:hidden;font-family:'OpenSansRegular'}.treemap-widget .desc .amount{font-size:1.4em;color:#fff;font-weight:normal;margin:.1em}.treemap-widget .desc .lbl{font-size:11px;line-height:15px;padding-left:2px;font-weight:300;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}#_tooltip{background-color:#333;color:#fff;padding:4px 6px} -------------------------------------------------------------------------------- /build/0.5.1/openspending.min.css: -------------------------------------------------------------------------------- 1 | .openspending-bt{position:relative;overflow:hidden}.openspending-bt .label{position:absolute;color:#fff;text-align:center;cursor:default}.openspending-bt .amount{font-family:Georgia,sans-serif;font-size:16px}.openspending-bt .desc{font-family:sans-serif;font-size:11px}.openspending-bt .label2{position:absolute;color:#000;text-align:center;cursor:default;font-size:11px;font-family:sans-serif;margin-top:5px}.openspending-bt .label2 span{background:#fff}.loading{z-index:1000;position:absolute;width:700px;height:400px}.openspending-bt-wrapper .tooltip{max-width:220px;border:1px solid #999;position:absolute;background:#fff;z-index:9999;box-shadow:3px 3px 0 rgba(0,0,0,.2);border-radius:2px;font-family:sans-serif;font-size:13px;padding:4px}.openspending-bt-wrapper .tooltip .header{padding:6px}.openspending-bt-wrapper .tooltip .header .icon{width:38px;height:38px;float:left;background:#600;border-radius:19px;margin-right:8px}.openspending-bt .tooltip svg{width:100px;height:100px;fill:black;display:block;position:relative;visibility:visible;z-index:10000}.openspending-bt .tooltip svg path{fill-opacity:1;visiblity:visible}.openspending-bt-wrapper .tooltip .row{clear:both;border-top:1px solid #999;padding:6px}#tooltip{position:absolute;z-index:3000;background-color:#fff;padding:5px;border:1px solid #999;box-shadow:3px 3px 0 rgba(0,0,0,.2);border-radius:2px;font-family:sans-serif;font-size:13px;padding:4px;max-width:200px}#tooltip .amount{font-weight:bold}#tooltip h3,#tooltip div{margin:0}p#vtip #vtipArrow{position:absolute;top:-10px;left:5px}.slice{display:inline-block;text-align:center}.controls{vertical-align:top}.salary,.tax{width:15%;display:inline-block}.salary{text-align:left}.tax{text-align:right}.salary p,.tax p{color:#830242;font-size:1.2em;font-weight:bold;text-transform:uppercase}.indirects{margin:15px 0}.indirects label{color:#830242;font-size:1.2em}.indirects label input[type='checkbox']{display:inline-block;margin-right:2px}.slider{display:inline-block;text-align:center;width:70%}.slider .ui-widget-content{background:0;background-color:#830242;height:6px}.slider .ui-slider-horizontal .ui-slider-handle{background:url('../img/currency-slider.png') transparent no-repeat;height:34px;width:32px;border:0;cursor:move;margin-top:-0.4em;margin-left:-0.8em}.slider div#ticks{font-size:90%;margin-top:5px}.slider div.tick-min{float:left;margin-left:-5px}.slider div.tick-max{float:right;margin-right:-15px}path.bar{fill:#ccc}path.topline{fill:none;stroke-width:1.5px;stroke:#333}g.bar{opacity:.5}g.bar:hover,g.selected{opacity:1}text.dotlabel{opacity:0;font-size:60%}g.bar:hover text.dotlabel,g.selected text.dotlabel{opacity:1}text.yearlabel{font-size:70%}g.axis path,g.axis line{fill:none;stroke:#aaa}g.axis text{font-size:70%;fill:#aaa}.bar rect{fill:#000;stroke:#FFF;stroke-width:1px;opacity:.5}.bar:hover rect{opacity:.7}ul.sb-breadcrumbs{padding:0;margin:0}ul.sb-breadcrumbs li{display:inline;margin-right:10px}ul.sb-breadcrunmbs li:hover{text-decoration:underline}svg body{margin:0}ul.sb-breadcrumbs li:before{color:#ccc;content:">"}.ui-tooltip-content .amount{font-size:20px;font-weight:normal;font-family:Palatino,Georgia;border-top:1px dashed #ccc;padding-top:8px;margin:5px 0 3px}.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:180px;min-width:50px;font-size:12px;line-height:15px;z-index:15000}.ui-tooltip-fluid{display:block;visibility:hidden;position:static !important;float:left !important}.ui-tooltip-content{position:relative;padding:5px 9px;overflow:hidden;border-width:1px;border-style:solid;text-align:left;word-wrap:break-word;overflow:hidden}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border-width:1px 1px 0;border-style:solid;font-weight:bold}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0 !important}/*! Default close button class */.ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid}* html .ui-tooltip-titlebar .ui-state-default{top:16px}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}/*! Default tooltip style */.ui-tooltip-default .ui-tooltip-titlebar,.ui-tooltip-default .ui-tooltip-content{border-color:#777;background-color:#fff;color:#000;border-radius:0 0 5px 5px;box-shadow:3px 3px 5px rgba(0,0,0,.3)}.ui-tooltip-default .ui-tooltip-titlebar{background-color:#222;color:#fff;border-radius:5px 5px 0 0;font-size:12px;font-weight:300;font-family:"OpenSansLight","Helvetica Neue",Helvetica,Arial,sans-serif}.ui-tooltip-default .ui-tooltip-icon{border-color:#CCC;background:#f1f1f1;color:#777}.ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111}.treemap-widget{position:relative;overflow:hidden;cursor:pointer;height:100%;color:#fff;font-family:Share;font-size:.8em;font-weight:bold}.treemap-widget div.desc{padding:.8em;font-weight:normal;overflow:hidden;font-family:'OpenSansRegular'}.treemap-widget .desc .amount{font-size:1.4em;color:#fff;font-weight:normal;margin:.1em}.treemap-widget .desc .lbl{font-size:11px;line-height:15px;padding-left:2px;font-weight:300;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}#_tooltip{background-color:#333;color:#fff;padding:4px 6px} -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # Demos 2 | 3 | This is a page featuring demos of some of the visualizations that can 4 | be driven using OpenSpending. The basic idea is to drive these 5 | visualizations from 6 | [partially aggregated](http://labs.openspending.org/osep/07-aggregation/) 7 | CSV files of spending data along with metadata provided in the 8 | associated [datapackage.json](http://dataprotocols.org/data-packages/) 9 | file. All of the examples below are driven from aggregations of the 10 | [main CSV file](https://github.com/openspending/dataset-cra/blob/master/data/cra.csv) 11 | found in the 12 | [UK Country Regional Analysis](https://github.com/openspending/dataset-cra) 13 | datapackage which is a database of UK government spending. Currently, 14 | metadata such as `currency`, `aggregated_csv_url`, and 15 | `amount_col_name` are manually passed to the visualization code. You 16 | can see the basic usage example in the `index.html` files of the 17 | visualizations below: 18 | 19 | ## Treemap 20 | 21 | ![Treemap](/demo/treemap.png) 22 | 23 | The partially aggregated CSV file driving the 24 | [Treemap](/demo/treemap/) visualization in the format: 25 | 26 | cofog_level1_code,dept_code,value 27 | 01,DFT004,425530000.0 28 | 03,NIO081,7368105000.0 29 | 03,NIE099,589154000.0 30 | 31 | ## BubbleTree 32 | 33 | ![BubbleTree](/demo/bubbletree.png) 34 | 35 | Likewise, the partially aggregated CSV file driving the 36 | [BubbleTree](/demo/bubbletree/) visualization is in the format: 37 | 38 | cofog_level1_code,dept_code,value 39 | 01,DFT004,425530000.0 40 | 03,NIO081,7368105000.0 41 | 03,NIE099,589154000.0 42 | 43 | 44 | ## Time Series 45 | 46 | ![Time Series](/demo/timeseries.png) 47 | 48 | The partially aggregated CSV file driving the 49 | [Time Series](/demo/timeseries/) visualization is only slightly 50 | modified by aggregating by the year dimension before the rest. 51 | 52 | year,cofog_level1_code,dept_code,value 53 | 2010,10,Dept030,106000000.00999999 54 | 2006,04,Welsh LG Adjustment/Input,522305000.0 55 | 2008,04,Dept084,3757412999.9800014 56 | -------------------------------------------------------------------------------- /demo/bubbletree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/demo/bubbletree.png -------------------------------------------------------------------------------- /demo/bubbletree/by-cofog1-then-cofog2.csv: -------------------------------------------------------------------------------- 1 | cofog_level1_code,cofog_level2_code,amount 2 | "01","",4073618999.97 3 | "01","01.1",9271288539.670006 4 | "01","01.2",4297096000 5 | "01","01.3",617983399.9399996 6 | "01","01.4",122494000 7 | "01","01.5",30205202.009999998 8 | "01","01.6",545529146.5199999 9 | "01","01.7",28749000000 10 | "01","01.8",-1802142000 11 | "02","",50877999.989999995 12 | "02","02.1",27465015999.989998 13 | "02","02.2",39559330.620000005 14 | "02","02.3",1689066000 15 | "02","02.4",620605000 16 | "02","02.5",2283863000 17 | "03","",13550373999.99 18 | "03","03.1",5815975898.09 19 | "03","03.2",556828343.52 20 | "03","03.3",6236140999.990001 21 | "03","03.4",3811909000.03 22 | "03","03.5",14110999.979999999 23 | "03","03.6",462957999.9800001 24 | "04","",973854999.9900002 25 | "04","04.1",6057552220.029997 26 | "04","04.2",5112556999.949999 27 | "04","04.3",1381916702.04 28 | "04","04.4",43656999.980000004 29 | "04","04.5",19987997550.849995 30 | "04","04.6",467439999.97999996 31 | "04","04.7",153050999.99 32 | "04","04.8",2765363000.050004 33 | "04","04.9",822178580.76 34 | "05","",4079245999.99 35 | "05","05.1",2436937350.9799995 36 | "05","05.2",45205000.010000005 37 | "05","05.3",236834999.9799999 38 | "05","05.4",489919000.01000005 39 | "05","05.5",341631000.01 40 | "05","05.6",1693164000.0000017 41 | "06","",5907940999.98 42 | "06","06.1",3689994960.560001 43 | "06","06.2",680919287.1700001 44 | "06","06.3",967707000.0 45 | "06","06.4",54093000 46 | "06","06.5",8529000 47 | "06","06.6",196849851.82 48 | "07","",277672000.0199999 49 | "07","07.1",91917758000 50 | "07","07.4",1703771999.9999998 51 | "07","07.5",609336999.98 52 | "08","",3721951999.9999995 53 | "08","08.1",1333691000.02 54 | "08","08.2",2347440219.5999994 55 | "08","08.3",3566269999.9900002 56 | "08","08.4",40558000.010000005 57 | "08","08.5",108969000.02 58 | "08","08.6",110206000.0 59 | "09","",39855276000.00001 60 | "09","09.1",4463174500.7 61 | "09","09.2",14245918630.730005 62 | "09","09.3",128974000 63 | "09","09.4",10330972133.250004 64 | "09","09.5",610786999.99 65 | "09","09.6",801918330.9200001 66 | "09","09.7",37992999.99 67 | "09","09.8",2446302927.669997 68 | "10","",34064858999.98 69 | "10","10.1",27912940998.639973 70 | "10","10.2",65847561999.929985 71 | "10","10.3",1810551000.01 72 | "10","10.4",22501366000.01 73 | "10","10.5",4587793000.01 74 | "10","10.6",2715944000.01 75 | "10","10.7",15524320919.879997 76 | "10","10.8",-13000 77 | "10","10.9",2178014136.36 78 | -------------------------------------------------------------------------------- /demo/bubbletree/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bubbletree Visualization Demo 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /demo/timeseries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/demo/timeseries.png -------------------------------------------------------------------------------- /demo/timeseries/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Time Series Visualization Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /demo/treemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/demo/treemap.png -------------------------------------------------------------------------------- /demo/treemap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Treemap Visualization Demo 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Mon Apr 20 2015 13:03:10 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha','sinon-chai'], 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | "lib/vendor/jquery.js", 18 | "lib/vendor/underscore.js", 19 | "lib/vendor/backbone.js", 20 | "lib/vendor/accounting.js", 21 | "lib/boot.js", 22 | "lib/aggregator.js", 23 | "lib/datastore.js", 24 | "lib/main.js", 25 | "lib/model.js", 26 | "lib/utils/gdocs.js", 27 | "lib/utils/tree.js", 28 | "lib/utils/utils.js", 29 | "lib/widgets.js", 30 | 'tests/fixtures.js', 31 | 'tests/**/*.coffee' 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [ 37 | '**/*.swp' 38 | ], 39 | 40 | 41 | // preprocess matching files before serving them to the browser 42 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 43 | preprocessors: { 44 | '**/*.coffee': ['coffee'], 45 | }, 46 | 47 | 48 | // test results reporter to use 49 | // possible values: 'dots', 'progress' 50 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 51 | reporters: ['progress'], 52 | 53 | 54 | // web server port 55 | port: 9876, 56 | 57 | 58 | // enable / disable colors in the output (reporters and logs) 59 | colors: true, 60 | 61 | 62 | // level of logging 63 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 64 | logLevel: config.LOG_INFO, 65 | 66 | 67 | // enable / disable watching file and executing tests whenever any file changes 68 | autoWatch: true, 69 | 70 | 71 | // start these browsers 72 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 73 | browsers: ['PhantomJS'], 74 | 75 | 76 | // Continuous Integration mode 77 | // if true, Karma captures browsers, runs the tests and exits 78 | singleRun: false 79 | }); 80 | }; 81 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/lib/.gitignore -------------------------------------------------------------------------------- /lib/vendor/Tween.js: -------------------------------------------------------------------------------- 1 | // Tween.js - http://github.com/sole/tween.js 2 | var TWEEN=TWEEN||function(){var a,e,c,d,f=[];return{start:function(g){c=setInterval(this.update,1E3/(g||60))},stop:function(){clearInterval(c)},add:function(g){f.push(g)},remove:function(g){a=f.indexOf(g);a!==-1&&f.splice(a,1)},update:function(){a=0;e=f.length;for(d=(new Date).getTime();a1?1:b;i=n(b);for(h in c)a[h]=e[h]+c[h]*i;l!==null&&l.call(a,i);if(b==1){m!==null&&m.call(a);k!==null&&k.start();return false}return true}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a}; 5 | TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a}; 6 | TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1}; 7 | TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)}; 8 | TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);return-(c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/d))}; 9 | TWEEN.Easing.Elastic.EaseOut=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);return c*Math.pow(2,-10*a)*Math.sin((a-e)*2*Math.PI/d)+1}; 10 | TWEEN.Easing.Elastic.EaseInOut=function(a){var e,c=0.1,d=0.4;if(a==0)return 0;if(a==1)return 1;d||(d=0.3);if(!c||c<1){c=1;e=d/4}else e=d/(2*Math.PI)*Math.asin(1/c);if((a*=2)<1)return-0.5*c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/d);return c*Math.pow(2,-10*(a-=1))*Math.sin((a-e)*2*Math.PI/d)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1}; 11 | TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375}; 12 | TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5}; 13 | -------------------------------------------------------------------------------- /lib/vendor/bubbletree/2.0/bubbletree.cofog.js: -------------------------------------------------------------------------------- 1 | /* 2 | * BubbleTree Style for COFOG taxonomy 3 | * 4 | */ 5 | 6 | var BubbleTree = BubbleTree || {}; 7 | BubbleTree.Styles = BubbleTree.Styles || {}; 8 | 9 | BubbleTree.Styles.Cofog1 = { 10 | '01': { icon: 'government-uk.svg', color: '#C75746' }, 11 | '02': { icon: 'defence.svg', color: '#0AB971' }, 12 | '03': { icon: 'order-safety.svg', color: '#EC2406' }, 13 | '04': { icon: 'social-systems.svg', color: '#790586' }, 14 | '05': { icon: 'environment.svg', color: '#2A3A03' }, 15 | '06': { icon: 'our-streets.svg', color: '#D33673' }, 16 | '07': { icon: 'health.svg', color: '#4E6D00' }, 17 | '08': { icon: 'culture.svg', color: '#938626' }, 18 | '09': { icon: 'education.svg' }, 19 | '10': { icon: 'helping-others.svg', color: '#935B3B' } 20 | } 21 | 22 | BubbleTree.Styles.Cofog2 = { 23 | '01.1': { icon: 'legislative.svg' }, 24 | '01.2': { icon: 'aid.svg' }, 25 | '01.3': { icon: 'misc-services.svg' }, 26 | '01.7': { icon: 'public-debt.svg' }, 27 | 28 | '02.1': { icon: 'military.svg' }, 29 | '02.2': { icon: 'civil-defence.svg' }, 30 | '02.3': { icon: 'foreign-military-aid.svg' }, 31 | '02.4': { icon: 'defence-research.svg' }, 32 | '02.5': { icon: 'defence-admin.svg' }, 33 | 34 | '03.1': { icon: 'police.svg' }, 35 | '03.2': { icon: 'fire-brigade.svg' }, 36 | '03.3': { icon: 'courts.svg' }, 37 | '03.4': { icon: 'prisons.svg' }, 38 | '03.5': { icon: 'rd-order-safety.svg' }, 39 | '03.6': { icon: 'admin-order-safety.svg' }, 40 | 41 | '04.1': { icon: 'social-systems.svg' }, 42 | '04.2': { icon: 'farms.svg' }, 43 | '04.3': { icon: 'energy.svg' }, 44 | '04.4': { icon: 'manufactoring-construction.svg' }, 45 | '04.5': { icon: 'transport.svg' }, 46 | '04.6': { icon: 'police.svg' }, 47 | '04.7': { icon: 'police.svg' }, 48 | //'04.8': { icon: 'rd-eco.svg' }, 49 | '04.9': { icon: 'police.svg' }, 50 | 51 | '05.1': { icon: 'waste.svg' }, 52 | '05.2': { icon: 'toilet.svg' }, 53 | '05.3': { icon: 'pollution.svg' }, 54 | '05.4': { icon: 'tree.svg' }, 55 | '05.6': { icon: 'environment-admin.svg' }, 56 | 57 | '06.1': { icon: 'housing.svg' }, 58 | '06.2': { icon: 'community.svg' }, 59 | '06.3': { icon: 'water.svg' }, 60 | '06.4': { icon: 'street-lights.svg' }, 61 | 62 | '07.1': { icon: 'medical-supplies.svg' }, 63 | '07.2': { icon: 'health.svg' }, 64 | '07.3': { icon: 'hospital.svg' }, 65 | 66 | '08.2': { icon: 'culture.svg' }, 67 | '08.1': { icon: 'sports.svg' }, 68 | '08.3': { icon: 'media.svg' }, 69 | 70 | '10.1': { icon: 'helping-others.svg' }, 71 | '10.2': { icon: 'old-age.svg' }, 72 | '10.4': { icon: 'family.svg' }, 73 | '10.7': { icon: 'family2.svg' } 74 | 75 | }; 76 | 77 | BubbleTree.Styles.Cofog3 = { 78 | 79 | '01.1.1': { icon: 'legislative.svg' }, 80 | '01.1.2': { icon: 'pig.svg' }, 81 | '01.1.3': { icon: 'worldmap.svg' }, 82 | '01.2.1': { icon: 'aid-developing-countries.svg' }, 83 | '01.2.2': { icon: 'economic-aid.svg' }, 84 | '01.3.1': { icon: 'human-resources.svg' }, 85 | '01.3.2': { icon: 'planning.svg' }, 86 | '01.3.3': { icon: 'research.svg' }, 87 | 88 | '04.1.1': { icon: 'social-systems.svg' }, 89 | '04.1.2': { icon: 'labour.svg' }, 90 | '04.2.1': { icon: 'farms.svg' }, 91 | '04.2.2': { icon: 'forest.svg' }, 92 | '04.2.3': { icon: 'fishing.svg' }, 93 | '04.3.1': { icon: 'coal.svg' }, 94 | '04.3.2': { icon: 'petrol.svg' }, 95 | '04.3.3': { icon: 'nuclear.svg' }, 96 | '04.3.4': { icon: 'fuel.svg' }, 97 | '04.3.5': { icon: 'electricity.svg' }, 98 | '04.3.6': { icon: 'wind.svg' }, 99 | '04.5.1': { icon: 'car.svg' }, 100 | '04.5.2': { icon: 'anchor.svg' }, 101 | '04.5.3': { icon: 'railways.svg' }, 102 | '04.5.4': { icon: 'airplane.svg' }, 103 | 104 | '07.1.1': { icon: 'medical-supplies.svg' }, 105 | '07.1.2': { icon: 'other-medical-products.svg' }, 106 | '07.1.3': { icon: 'wheelchair.svg' }, 107 | '07.2.1': { icon: 'health.svg' }, 108 | '07.2.2': { icon: 'microscope.svg' }, 109 | '07.2.2': { icon: 'dental.svg' }, 110 | '07.3.1': { icon: 'hospital.svg' }, 111 | '07.3.2': { icon: 'hospital-specialized.svg' }, 112 | '07.3.2': { icon: 'dental.svg' }, 113 | 114 | '10.1.2': { icon: 'helping-others.svg' } 115 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openspendingjs", 3 | "shortname": "openspending", 4 | "version": "0.5.1", 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-concat": "~0.3.0", 8 | "grunt-yui-compressor": "~0.3.0", 9 | "grunt-contrib-copy": "~0.4.1", 10 | "grunt-contrib-compress": "~0.5.3", 11 | "grunt-contrib-clean": "~0.5.0", 12 | "grunt-karma": "^0.10.1", 13 | "karma-coffee-preprocessor": "^0.2.1", 14 | "karma-mocha": "^0.1.10", 15 | "karma-mocha-chai-sinon": "0.0.7", 16 | "karma-phantomjs-launcher": "^0.1.4", 17 | "karma-sinon-chai": "^0.3.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /publish_assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION=`git describe --always` 4 | s3cmd -P -M -f --delete-removed --rexclude '.git/.*' --rexclude 'flash/.*' --rexclude '.DS_Store' sync . s3://assets.openspending.org/openspendingjs/$VERSION/ 5 | 6 | -------------------------------------------------------------------------------- /releases/openspendingjs-0.1.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.1.0.tgz -------------------------------------------------------------------------------- /releases/openspendingjs-0.1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.1.0.zip -------------------------------------------------------------------------------- /releases/openspendingjs-0.2.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.2.0.tgz -------------------------------------------------------------------------------- /releases/openspendingjs-0.2.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.2.0.zip -------------------------------------------------------------------------------- /releases/openspendingjs-0.2.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.2.1.tgz -------------------------------------------------------------------------------- /releases/openspendingjs-0.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.2.1.zip -------------------------------------------------------------------------------- /releases/openspendingjs-0.3.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.3.0.tgz -------------------------------------------------------------------------------- /releases/openspendingjs-0.3.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.3.0.zip -------------------------------------------------------------------------------- /releases/openspendingjs-0.4.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.4.0.tgz -------------------------------------------------------------------------------- /releases/openspendingjs-0.4.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openspending-archive/openspendingjs/aac0e3ae6b3aac7f07d462ec2bf30c9b393e97e1/releases/openspendingjs-0.4.0.zip -------------------------------------------------------------------------------- /src/css/bubbletree.css: -------------------------------------------------------------------------------- 1 | .openspending-bt { 2 | position: relative; 3 | overflow: hidden; 4 | } 5 | 6 | .openspending-bt .label { 7 | position: absolute; 8 | color: #fff; 9 | text-align: center; 10 | cursor: default; 11 | } 12 | 13 | .openspending-bt .amount { 14 | font-family: Georgia, sans-serif; 15 | font-size: 16px; 16 | } 17 | 18 | .openspending-bt .desc { 19 | font-family: sans-serif; 20 | font-size: 11px; 21 | 22 | } 23 | 24 | .openspending-bt .label2 { 25 | position: absolute; 26 | color: #000; 27 | text-align: center; 28 | cursor: default; 29 | font-size: 11px; 30 | font-family: sans-serif; 31 | margin-top:5px; 32 | } 33 | 34 | .openspending-bt .label2 span { 35 | background: #fff; 36 | } 37 | 38 | .loading { 39 | z-index: 1000; 40 | position: absolute; 41 | width: 700px; 42 | height: 400px; 43 | } 44 | 45 | .openspending-bt-wrapper .tooltip { 46 | max-width: 220px; 47 | border: 1px solid #999; 48 | position: absolute; 49 | background: #fff; 50 | z-index: 9999; 51 | box-shadow: 3px 3px 0px rgba(0,0,0,.2); 52 | border-radius: 2px; 53 | font-family: sans-serif; 54 | font-size: 13px; 55 | padding: 4px; 56 | } 57 | 58 | .openspending-bt-wrapper .tooltip .header { 59 | padding: 6px; 60 | } 61 | 62 | .openspending-bt-wrapper .tooltip .header .icon { 63 | width: 38px; 64 | height: 38px; 65 | float: left; 66 | background: #600; 67 | border-radius: 19px; 68 | margin-right: 8px; 69 | } 70 | 71 | .openspending-bt .tooltip svg { 72 | width: 100px; height: 100px; fill: black; display: block; position: relative; visibility: visible; 73 | z-index: 10000; 74 | } 75 | 76 | .openspending-bt .tooltip svg path { 77 | fill-opacity: 1; visiblity: visible; 78 | } 79 | 80 | .openspending-bt-wrapper .tooltip .row { 81 | clear: both; 82 | border-top: 1px solid #999; padding: 6px; 83 | } 84 | 85 | 86 | #tooltip { 87 | position: absolute; 88 | z-index: 3000; 89 | background-color: #fff; 90 | padding: 5px; 91 | 92 | border: 1px solid #999; 93 | box-shadow: 3px 3px 0px rgba(0,0,0,.2); 94 | border-radius: 2px; 95 | font-family: sans-serif; 96 | font-size: 13px; 97 | padding: 4px; 98 | max-width: 200px; 99 | } 100 | 101 | #tooltip .amount { 102 | font-weight: bold; 103 | } 104 | 105 | #tooltip h3, #tooltip div { margin: 0; } 106 | 107 | p#vtip #vtipArrow { position: absolute; top: -10px; left: 5px } 108 | -------------------------------------------------------------------------------- /src/css/dailybread.css: -------------------------------------------------------------------------------- 1 | .slice { 2 | display: inline-block; 3 | text-align: center; 4 | } 5 | 6 | .controls { 7 | vertical-align: top; 8 | } 9 | 10 | .salary, .tax { 11 | width: 15%; 12 | display: inline-block; 13 | } 14 | 15 | .salary { 16 | text-align: left; 17 | } 18 | 19 | .tax { 20 | text-align: right; 21 | } 22 | 23 | .salary p, .tax p { 24 | color: #830242; 25 | font-size: 1.2em; 26 | font-weight: bold; 27 | text-transform: uppercase; 28 | } 29 | 30 | .indirects { 31 | margin: 15px 0px; 32 | } 33 | 34 | .indirects label { 35 | color: #830242; 36 | font-size: 1.2em; 37 | } 38 | 39 | .indirects label input[type='checkbox'] { 40 | display: inline-block; 41 | margin-right: 2px; 42 | } 43 | 44 | /** Slider */ 45 | 46 | .slider { 47 | display: inline-block; 48 | text-align: center; 49 | width: 70%; 50 | } 51 | 52 | .slider .ui-widget-content { 53 | background: none; 54 | background-color: #830242; 55 | height: 6px; 56 | } 57 | 58 | .slider .ui-slider-horizontal .ui-slider-handle { 59 | background: url('../img/currency-slider.png') transparent no-repeat; 60 | height: 34px; 61 | width: 32px; 62 | border: none; 63 | cursor: move; 64 | margin-top: -0.4em; 65 | margin-left: -0.8em; 66 | } 67 | 68 | .slider div#ticks { 69 | font-size: 90%; 70 | margin-top: 5px; 71 | } 72 | 73 | .slider div.tick-min { 74 | float: left; 75 | margin-left: -5px; 76 | } 77 | 78 | .slider div.tick-max { 79 | float: right; 80 | margin-right: -15px; 81 | } 82 | -------------------------------------------------------------------------------- /src/css/linebars.css: -------------------------------------------------------------------------------- 1 | path.bar { 2 | fill: #CCCCCC; 3 | } 4 | 5 | path.topline { 6 | fill: none; 7 | stroke-width: 1.5px; 8 | stroke: #333333; 9 | } 10 | g.bar { 11 | opacity: 0.5; 12 | } 13 | 14 | g.bar:hover, g.selected { 15 | opacity: 1; 16 | } 17 | 18 | text.dotlabel { 19 | opacity: 0; 20 | font-size: 60%; 21 | } 22 | 23 | g.bar:hover text.dotlabel, g.selected text.dotlabel { 24 | opacity: 1; 25 | } 26 | 27 | text.yearlabel { 28 | font-size: 70%; 29 | } 30 | 31 | g.axis path, g.axis line { 32 | fill: none; 33 | stroke: #AAAAAA; 34 | } 35 | 36 | g.axis text { 37 | font-size: 70%; 38 | fill: #AAAAAA; 39 | } 40 | -------------------------------------------------------------------------------- /src/css/stackedbar.css: -------------------------------------------------------------------------------- 1 | .bar rect { 2 | fill: #000; 3 | stroke: #FFF; 4 | stroke-width: 1px; 5 | opacity: 0.5; 6 | } 7 | .bar:hover rect { 8 | opacity: 0.7; 9 | } 10 | 11 | ul.sb-breadcrumbs { 12 | padding: 0; 13 | margin: 0; 14 | } 15 | 16 | ul.sb-breadcrumbs li { 17 | display: inline; 18 | margin-right: 10px; 19 | } 20 | 21 | ul.sb-breadcrunmbs li:hover { 22 | text-decoration: underline; 23 | } 24 | 25 | svg body { 26 | margin: 0; 27 | } 28 | 29 | ul.sb-breadcrumbs li:before { 30 | color: #CCCCCC; 31 | content: ">"; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/css/tooltips.css: -------------------------------------------------------------------------------- 1 | .ui-tooltip-content .amount { 2 | font-size: 20px; 3 | font-weight: normal; 4 | font-family: Palatino, Georgia; 5 | border-top: 1px dashed #ccc; 6 | padding-top: 8px; 7 | margin: 5px 0 3px; 8 | } 9 | 10 | 11 | /* 12 | * qTip2 - Pretty powerful tooltips 13 | * http://craigsworks.com/projects/qtip2/ 14 | * 15 | * Version: nightly 16 | * Copyright 2009-2010 Craig Michael Thompson - http://craigsworks.com 17 | * 18 | * Dual licensed under MIT or GPLv2 licenses 19 | * http://en.wikipedia.org/wiki/MIT_License 20 | * http://en.wikipedia.org/wiki/GNU_General_Public_License 21 | * 22 | * Date: Mon Nov 21 13:18:18.0000000000 2011 23 | */ 24 | 25 | 26 | /* Core qTip styles */ 27 | .ui-tooltip, .qtip{ 28 | position: absolute; 29 | left: -28000px; 30 | top: -28000px; 31 | display: none; 32 | 33 | max-width: 180px; 34 | min-width: 50px; 35 | 36 | font-size: 12px; 37 | line-height: 15px; 38 | 39 | z-index: 15000; 40 | } 41 | 42 | /* Fluid class for determining actual width in IE */ 43 | .ui-tooltip-fluid{ 44 | display: block; 45 | visibility: hidden; 46 | position: static !important; 47 | float: left !important; 48 | } 49 | 50 | .ui-tooltip-content{ 51 | position: relative; 52 | padding: 5px 9px; 53 | overflow: hidden; 54 | 55 | border-width: 1px; 56 | border-style: solid; 57 | 58 | text-align: left; 59 | word-wrap: break-word; 60 | overflow: hidden; 61 | } 62 | 63 | .ui-tooltip-titlebar{ 64 | position: relative; 65 | min-height: 14px; 66 | padding: 5px 35px 5px 10px; 67 | overflow: hidden; 68 | 69 | border-width: 1px 1px 0; 70 | border-style: solid; 71 | 72 | font-weight: bold; 73 | } 74 | 75 | .ui-tooltip-titlebar + .ui-tooltip-content{ border-top-width: 0px !important; } 76 | 77 | /*! Default close button class */ 78 | .ui-tooltip-titlebar .ui-state-default{ 79 | position: absolute; 80 | right: 4px; 81 | top: 50%; 82 | margin-top: -9px; 83 | 84 | cursor: pointer; 85 | outline: medium none; 86 | 87 | border-width: 1px; 88 | border-style: solid; 89 | } 90 | 91 | * html .ui-tooltip-titlebar .ui-state-default{ top: 16px; } /* IE fix */ 92 | 93 | .ui-tooltip-titlebar .ui-icon, 94 | .ui-tooltip-icon .ui-icon{ 95 | display: block; 96 | text-indent: -1000em; 97 | } 98 | 99 | .ui-tooltip-icon, .ui-tooltip-icon .ui-icon{ 100 | -moz-border-radius: 3px; 101 | -webkit-border-radius: 3px; 102 | border-radius: 3px; 103 | } 104 | 105 | .ui-tooltip-icon .ui-icon{ 106 | width: 18px; 107 | height: 14px; 108 | 109 | text-align: center; 110 | text-indent: 0; 111 | font: normal bold 10px/13px Tahoma,sans-serif; 112 | 113 | color: inherit; 114 | background: transparent none no-repeat -100em -100em; 115 | } 116 | 117 | 118 | /* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */ 119 | .ui-tooltip-focus{ 120 | 121 | } 122 | 123 | /* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */ 124 | .ui-tooltip-hover{ 125 | 126 | } 127 | 128 | 129 | /*! Default tooltip style */ 130 | .ui-tooltip-default .ui-tooltip-titlebar, 131 | .ui-tooltip-default .ui-tooltip-content{ 132 | border-color: #777; 133 | background-color: #fff; 134 | color: #000; 135 | border-radius: 0 0 5px 5px; 136 | box-shadow: 3px 3px 5px rgba(0,0,0,.3); 137 | } 138 | 139 | .ui-tooltip-default .ui-tooltip-titlebar{ 140 | background-color: #222; 141 | color: #fff; 142 | border-radius: 5px 5px 0 0; 143 | font-size: 12px; 144 | font-weight: 300; 145 | font-family: "OpenSansLight","Helvetica Neue",Helvetica,Arial,sans-serif; 146 | } 147 | 148 | .ui-tooltip-default .ui-tooltip-icon{ 149 | border-color: #CCC; 150 | background: #F1F1F1; 151 | color: #777; 152 | 153 | } 154 | 155 | .ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{ 156 | border-color: #AAA; 157 | color: #111; 158 | } 159 | -------------------------------------------------------------------------------- /src/css/treemap.css: -------------------------------------------------------------------------------- 1 | .treemap-widget { 2 | position: relative; 3 | overflow: hidden; 4 | cursor: pointer; 5 | height: 100%; 6 | color: #fff; 7 | font-family: Share; 8 | font-size: 0.8em; 9 | font-weight: bold; 10 | } 11 | 12 | .treemap-widget div.desc { 13 | padding: 0.8em; 14 | font-weight: normal; 15 | overflow: hidden; 16 | font-family: 'OpenSansRegular'; 17 | } 18 | 19 | .treemap-widget .desc .amount { 20 | /*font-family: OpenSans, Georgia, serif;*/ 21 | font-size: 1.4em; 22 | color: #fff; 23 | font-weight: normal; 24 | margin: 0.1em; 25 | } 26 | 27 | .treemap-widget .desc .lbl { 28 | font-size: 11px; 29 | line-height: 15px; 30 | padding-left: 2px; 31 | font-weight: 300; 32 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 33 | } 34 | 35 | #_tooltip { 36 | background-color: #333; 37 | color: #fff; 38 | padding: 4px 6px; 39 | } 40 | -------------------------------------------------------------------------------- /src/svg/EC.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /src/svg/admin-culture.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 42 | 43 | -------------------------------------------------------------------------------- /src/svg/admin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /src/svg/aid-developing-countries.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 39 | 40 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/svg/aid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /src/svg/airplane.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 35 | 36 | -------------------------------------------------------------------------------- /src/svg/ambulance.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /src/svg/anchor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 28 | 29 | -------------------------------------------------------------------------------- /src/svg/books.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 29 | 30 | -------------------------------------------------------------------------------- /src/svg/car.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 31 | 32 | -------------------------------------------------------------------------------- /src/svg/coal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 22 | 23 | -------------------------------------------------------------------------------- /src/svg/community.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /src/svg/courts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 42 | 43 | -------------------------------------------------------------------------------- /src/svg/culture.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 41 | 42 | -------------------------------------------------------------------------------- /src/svg/dental.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /src/svg/dollar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/svg/economic-aid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 16 | 30 | 32 | 34 | 36 | 41 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/svg/education.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 33 | 34 | -------------------------------------------------------------------------------- /src/svg/energy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /src/svg/energy2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 19 | 20 | -------------------------------------------------------------------------------- /src/svg/euro.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/svg/foreign-military-aid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 38 | 39 | -------------------------------------------------------------------------------- /src/svg/fuel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/svg/health.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 35 | 36 | -------------------------------------------------------------------------------- /src/svg/hospital.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /src/svg/housing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /src/svg/island.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 29 | 30 | -------------------------------------------------------------------------------- /src/svg/legislative.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 31 | 32 | -------------------------------------------------------------------------------- /src/svg/media.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 20 | 21 | -------------------------------------------------------------------------------- /src/svg/medical-supplies.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/svg/microscope.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/svg/military.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 51 | 52 | -------------------------------------------------------------------------------- /src/svg/nuclear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /src/svg/other-medical.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /src/svg/our-streets.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /src/svg/petrol.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 32 | 33 | -------------------------------------------------------------------------------- /src/svg/pig.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 36 | 37 | -------------------------------------------------------------------------------- /src/svg/police.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 37 | 38 | -------------------------------------------------------------------------------- /src/svg/pollution.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 17 | 18 | -------------------------------------------------------------------------------- /src/svg/pound.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/svg/pound2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 17 | 18 | -------------------------------------------------------------------------------- /src/svg/primary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 29 | 30 | -------------------------------------------------------------------------------- /src/svg/public-debt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 36 | 38 | 40 | 41 | 43 | 44 | -------------------------------------------------------------------------------- /src/svg/railways.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 26 | 27 | -------------------------------------------------------------------------------- /src/svg/secondary-lower.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/svg/secondary-upper.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 36 | 37 | -------------------------------------------------------------------------------- /src/svg/social-systems.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 36 | 37 | -------------------------------------------------------------------------------- /src/svg/street-lights.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 26 | 27 | -------------------------------------------------------------------------------- /src/svg/toilet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /src/svg/unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | ? 8 | 9 | -------------------------------------------------------------------------------- /src/svg/waste.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /src/svg/water.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /src/svg/wind.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 16 | 25 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/utils/README.md: -------------------------------------------------------------------------------- 1 | # OpenSpending Utils 2 | 3 | The various OpenSpendingJS utils extend the OpenSpending object with their own objects. For example the amount utils can be found as OpenSpending.Amounts 4 | 5 | ## openspending.aggregator.js 6 | 7 | Aggregator functions to work directly with the OpenSpending platform's aggregation API (or related functions) This exposes: 8 | 9 | * **OpenSpending.Aggregator.configFromQueryString**: Function that create aggregation configuration from a query string. Optional parameter is the query string itself. If it isn't provided the function will use the current window location. 10 | * **OpenSpending.Aggregator.get**: Function that given an aggregation configuration gets the data via the OpenSpending platform API. 11 | 12 | ### Example of aggregation config 13 | 14 | Below is an example of an aggregation configuration 15 | 16 | { 17 | siteUrl: 'http://openspending.org', 18 | dataset: 'ukgov-finances-cra', 19 | drilldowns: ['from', 'to'], 20 | cuts: ['year:2012'], 21 | breakdown: 'region', 22 | rootNodeLabel: 'Total', 23 | localApiCache: 'aggregate.json', 24 | measure: 'amount', 25 | processEntry: function(e) { return e; }, 26 | callback: function (tree) {} 27 | } 28 | 29 | ## openspending.amounts.js 30 | 31 | Useful utils to work with amounts and currencies. Uses accounting.js to do the heavy lifting on formatting. This exposes: 32 | 33 | * **OpenSpending.Amounts.shorthand**: Function that takes in one parameter *amount* and returns a short hand format for the amount. Anything over 1 billion (e.g. 4.000.000.000) will be abbreviated with "bn" (e.g. 4bn). The same goes for million (m), and thousand (k). Anything lower then a thousand is shown with two decimals. 34 | * **OpenSpending.Amounts.format**: Function that takes in *amount*, *precision*, *currency* and formats the amount with according to the two other parameters. Precision is an integer that declares the number of decimal points. Currency is a three letter abbreviation for the currency (e.g. USD, GBP) 35 | * **OpenSpending.Amounts.currencySymbol**: Function that takes in a three letter abbreviation for a currency and returns the corresponding currency symbol (or the three letter abbreviation if it didn't find the symbol. 36 | * **OpenSpending.Amounts.currencySymbols**: A key/value object of three letter currency abbreviations and how they map to currency symbols. 37 | 38 | ## openspending.colors.js 39 | 40 | Color manipulation for OpenSpending that is useful to visualise data with fancy colors. This exposes: 41 | 42 | * **OpenSpending.Colors.DefaultPalette**: A list of default colors. The array has a getColor function that allows colors to be fetched from the default palette in a round robin fashin (as a circle). 43 | 44 | ## openspending.common.js 45 | 46 | Includes common utils that can come in handy in various different tasks. This exposes: 47 | 48 | * **OpenSpending.Common.parseQueryString**: Function that parses a URI query string and returns it as a key/value javascript object. Optional parameter is the query string itself. If it isn't provided the function will use the current window location. -------------------------------------------------------------------------------- /src/utils/openspending.colors.js: -------------------------------------------------------------------------------- 1 | /*! openspending.colors.js - Color palettes for OpenSpending 2 | * ------------------------------------------------------------------------ 3 | * 4 | * Copyright 2013 Open Knowledge Foundation 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // Define OpenSpending object (if used as a separate module) 20 | var OpenSpending = OpenSpending || {}; 21 | // Define Colors property 22 | OpenSpending.Colors = OpenSpending.Colors || {}; 23 | 24 | // Fallback color when something isn't found 25 | OpenSpending.Colors.Fallback = '#424242'; 26 | 27 | // Default color palette for openspendingjs 28 | OpenSpending.Colors.DefaultPalette = ["#CA221D", "#C22769", "#3F93E1", 29 | "#481B79", "#6AAC32", "#42928F", 30 | "#D32645", "#CD531C", "#EDC92D", 31 | "#A5B425", "#211D79", "#449256", 32 | "#7A2077", "#CA221D", "#E29826", 33 | "#44913D", "#2458A3", "#2458A3", 34 | "#14388C"]; 35 | 36 | // Cofog color palette 37 | OpenSpending.Colors.Cofog = { '01': '#C75746', '02': '#0AB971', 38 | '03': '#EC2406', '04': '#790586', 39 | '05': '#2A3A03', '06': '#D33673', 40 | '07': '#4E6D00', '08': '#938626', 41 | '09': '#EDC92D', '10': '#935B3B' 42 | }; 43 | 44 | OpenSpending.Colors.DefaultPalette.getColor = function (item, index, skip) { 45 | // getColor fetches the color of the index from an wrap around version 46 | // of the default palette (using modulo) 47 | var palette = this.slice(0); 48 | 49 | if (skip) { 50 | var idx = palette.indexOf(skip.toUpperCase()); // Find the index 51 | if(idx !== -1) palette.splice(idx, 1); // Remove it if really found! 52 | } 53 | 54 | if (index === undefined) { 55 | return OpenSpending.Colors.Fallback; 56 | } 57 | 58 | return palette[(index || 0) % (palette.length)]; 59 | }; 60 | 61 | 62 | OpenSpending.Colors.Cofog.getColor = function(item, index, skip) { 63 | // If item is string then it's the code, else we get it from item.name 64 | var code = (typeof item === 'string') ? item : (item.name || item.id); 65 | // We only want the top level of the code 66 | // (we're interested in the 10 in 10.1.1) 67 | if (code === undefined) { 68 | return OpenSpending.Colors.Fallback; 69 | } 70 | var top_level = code.substr(0, 2); 71 | return this[top_level] || OpenSpending.Colors.Fallback; 72 | }; -------------------------------------------------------------------------------- /src/utils/openspending.common.js: -------------------------------------------------------------------------------- 1 | /*! openspending.common.js - Common javascript utils for openspendingjs 2 | * ------------------------------------------------------------------------ 3 | * 4 | * Copyright 2013 Open Knowledge Foundation 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | 20 | var OpenSpending = OpenSpending || {}; 21 | OpenSpending.Common = OpenSpending.Common || {}; 22 | 23 | // Parse a URL query string (?xyz=abc...) into a javascript object. 24 | OpenSpending.Common.parseQueryString = function(querystring) { 25 | // Get query string (either provided or we get it from the current window 26 | var query = querystring || window.location.search.substring(1); 27 | 28 | // The javascript object we'll fill in and return 29 | var urlParams = {}; 30 | 31 | // Tiny cleanup function 32 | var clean = function (param) { 33 | // We replace all + with whitespace and return in unescaped 34 | return unescape(param.replace(/\+/g, " ")); 35 | }; 36 | 37 | // Parameter regular expression (even though they're not cool with urls 38 | var regexp = /([^&=]+)=?([^&]*)/g; 39 | // Object to hold the regexp matches 40 | var matches = undefined; 41 | 42 | // While the regular expression finds matches 43 | while (matches = regexp.exec(query)) { 44 | // Create a property in urlParams with the key and set the 45 | // parameter value as its value 46 | urlParams[clean(matches[1])] = clean(matches[2]); 47 | } 48 | 49 | // Return the parameter object 50 | return urlParams; 51 | }; 52 | -------------------------------------------------------------------------------- /src/utils/openspending.taxman.js: -------------------------------------------------------------------------------- 1 | /*! openspending.taxman.js - Taxman API tools 2 | * ------------------------------------------------------------------------ 3 | * 4 | * Copyright 2013 Open Knowledge Foundation 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | // Define OpenSpending object 20 | var OpenSpending = OpenSpending || {}; 21 | 22 | // Taxman constructor 23 | OpenSpending.Taxman = function( options ) { 24 | // To make taxes accessible from the instance we need 25 | // to assign this to self 26 | var self = this; 27 | this.taxes = undefined; 28 | 29 | // Create the configuration 30 | var config = $.extend(true, {}, OpenSpending.Taxman.defaults, options); 31 | 32 | // Provide a get function that fetches the taxes for the given amount 33 | this.get = function(income) { 34 | // First we parse the income in case it needs some changes (this 35 | // also sets it in the right place in the opts 36 | config.incomeparser(income); 37 | 38 | // Then we call the taxman api with the opts and the country 39 | var rq = $.getJSON( 40 | config.site + '/'+config.country+'?callback=?', 41 | config.opts) 42 | .done(function(data) { 43 | // We parse the taxes via the success function in the config 44 | // and set them as the instance variable taxes 45 | self.taxes = config.success(data); 46 | // Use callback 47 | config.callback(self.taxes); 48 | }); 49 | 50 | // Using a callback isn't necessary. We return the deferred in case 51 | // using it is preferred over callback. 52 | return rq; 53 | }; 54 | }; 55 | 56 | // Default configuraiton for 57 | OpenSpending.Taxman.defaults = { 58 | site: 'http://taxman.openspending.org', // Taxman url 59 | country: undefined, // Two letter country code 60 | opts: { }, // Options to pass into the taxman api call 61 | callback: function(taxes) { }, // Callback function (taxes are passed in) 62 | incomeparser: function(income) { // Parse income or assign differently 63 | this.opts.income = income; 64 | }, 65 | success: function(data) { return data }, // Get taxes from the taxman api call 66 | }; -------------------------------------------------------------------------------- /tests/fixtures.js: -------------------------------------------------------------------------------- 1 | var fixtures = { 2 | datasets: { 3 | sample : { 4 | "source_description": "LBHF raw spending data", 5 | "maintainer": null, 6 | "maintainer_email": null, 7 | "currency": "USD", 8 | "metadata_created": "2007-04-10T21:19:38", 9 | "relationships": [], 10 | "time_axis": "time.from.year", 11 | "metadata_modified": "2011-05-24T15:08:02.410149", 12 | "author": "mk270", 13 | "author_email": null, 14 | "source_format": "csv", 15 | "download_url": "http://mk.ucant.org/info/data/lbhf_line_2010.csv", 16 | "label": "London Borough of Hammersmith and Fulham Spending 2010", 17 | "state": "active", 18 | "version": null, 19 | "license_id": "uk-ogl", 20 | "description": "Spending data published by Hammersmith and Fulham council; collated from 12 monthly report", 21 | "tags": [ 22 | "lbhf", 23 | "openspending" 24 | ], 25 | "source_url": "http://mk.ucant.org/info/data/lbhf_line_2010.csv", 26 | "cubes": { 27 | "default": { 28 | "dimensions": [ 29 | "from", 30 | "currency", 31 | "spendingarea", 32 | "to", 33 | "amount", 34 | "year", 35 | "transactionid" 36 | ], 37 | "num_cells": 29 38 | } 39 | }, 40 | "name": "lbhf-spending-2010", 41 | "license": "OKD Compliant::UK Open Government Licence (OGL)", 42 | "notes_rendered": "

Spending data published by Hammersmith and Fulham council; collated from 12 monthly report

", 43 | "url": "http://www.spotlightonspend.org.uk/317/London+Borough+of+Hammersmith+and+Fulham/Spend/Annual", 44 | "ckan_url": "http://ckan.net/package/lbhf-spending-2010", 45 | "ratings_average": null, 46 | "ratings_count": 0, 47 | "source_id": "9661abbd-2816-4d58-8b20-3cb0eb770c69", 48 | "revision_id": "5ec06287-1781-4ac4-86fd-1d7472cb6e5b", 49 | "_id": "4df12d9b274fdcf0e4689ffb" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Suite 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /tests/linebars.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/spec/lib/aggregator.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/aggregator', -> 2 | describe 'OpenSpending.aggregatorConfigFromQueryString', -> 3 | qs = null 4 | res = null 5 | 6 | beforeEach -> 7 | qs = 'drilldown=abc|xyz&breakdown=region&cut=time.year:2011&page=5' 8 | res = OpenSpending.aggregatorConfigFromQueryString(qs) 9 | 10 | it 'should parse drilldowns', -> 11 | expect(res.drilldowns).to.eql(['abc', 'xyz']) 12 | 13 | it 'should parse breakdown', -> 14 | expect(res.breakdown).to.eql('region') 15 | 16 | it 'should parse cuts', -> 17 | expect(res.cuts).to.eql(['time.year:2011']) 18 | -------------------------------------------------------------------------------- /tests/spec/lib/boot.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/boot', -> 2 | it 'should define the OpenSpending object', -> 3 | # NB: this test doesn't *really* test this, as it just tests that said 4 | # variable is available after all the source files have loaded. 5 | # Nonetheless, it serves as a statement of intent. 6 | expect(OpenSpending).to.exist 7 | 8 | it 'should define OpenSpending.getGlobal() to return the environment global object', -> 9 | expect(OpenSpending.getGlobal()).to.equal(module ? window) 10 | 11 | it 'should define OpenSpending.{jQuery,$} for OpenSpending\'s use', -> 12 | expect(OpenSpending.jQuery).to.exist 13 | expect(OpenSpending.$).to.exist 14 | expect(OpenSpending.jQuery.ajax).to.exist 15 | expect(OpenSpending.$.ajax).to.exist 16 | 17 | it 'should define OpenSpending.ajaxError, an ajax error handler', -> 18 | g = OpenSpending.getGlobal() 19 | if g.hasOwnProperty('console') 20 | stub = sinon.stub(g.console, 'error') 21 | else 22 | stub = sinon.stub(g, 'alert') 23 | 24 | callback = OpenSpending.ajaxError('msg') 25 | callback('rq', 'x', 'status') 26 | expect(stub).to.have.been.calledOnce 27 | stub.restore() 28 | 29 | -------------------------------------------------------------------------------- /tests/spec/lib/datastore.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/datastore', -> 2 | describe 'OpenSpending.Datastore', -> 3 | it 'should load config from its constructor argument', -> 4 | config = { 5 | endpoint: "http://my.openspending.org/" 6 | } 7 | datastore = OpenSpending.Datastore(config) 8 | expect(datastore.config.endpoint).to.eql(config.endpoint) 9 | -------------------------------------------------------------------------------- /tests/spec/lib/main.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/main', -> 2 | -------------------------------------------------------------------------------- /tests/spec/lib/model.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/model', -> 2 | describe 'OpenSpending.Model', -> 3 | model = null 4 | 5 | it 'should load a config from its constructor argument', -> 6 | model = OpenSpending.Model(endpoint: 'http://example.com/') 7 | expect(model.config.endpoint).to.equal('http://example.com/') 8 | 9 | describe '.Dataset', -> 10 | dataset = null 11 | server = null 12 | 13 | beforeEach -> 14 | model = OpenSpending.Model(endpoint: 'http://example.com/') 15 | dataset = new model.Dataset(name: 'test-dataset', title: 'My New Dataset') 16 | 17 | 18 | it 'should construct dataset objects', -> 19 | expect(dataset).to.exist 20 | 21 | describe '.url()', -> 22 | it 'should return the API endpoint for the dataset object', -> 23 | expect(dataset.url()).to.equal('http://example.com/test-dataset.json') 24 | 25 | describe '.drilldownDimensions()', -> 26 | it 'should return the list of drilldown dimensions', -> 27 | ds = new model.Dataset(fixtures.datasets.sample) 28 | expect(ds.drilldownDimensions()).to.have.length(4) 29 | 30 | # describe '.fetch()', -> 31 | # server = null 32 | 33 | # beforeEach -> 34 | # server = sinon.fakeServer.create() 35 | 36 | # afterEach -> 37 | # server.restore() 38 | 39 | # it 'should fetch dataset metadata from the server', -> 40 | # dsId = 'lbhf-spending-2010' 41 | 42 | # server.respondWith( 43 | # "GET", "http://example.com/#{dsId}.json", 44 | # [200, { "Content-Type": "application/json" }, '{ "label": "London Borough of ..." }'] 45 | # ) 46 | 47 | # ds = new model.Dataset(id: dsId, name: dsId) 48 | # ds.fetch() 49 | 50 | # expect(ds.get('label')).to.equal("London Borough of ...") 51 | -------------------------------------------------------------------------------- /tests/spec/lib/utils/tree.coffee: -------------------------------------------------------------------------------- 1 | sampleTree = -> 2 | id: 'root' 3 | name: 'root' 4 | data: {} 5 | children: [ 6 | { 7 | id: 'c1' 8 | name: 'c1' 9 | children: [ 10 | { 11 | id: 'c1c1' 12 | value: 10 13 | children: [] 14 | } 15 | ] 16 | } 17 | { 18 | id: 'c2' 19 | value: 20 20 | children: [] 21 | } 22 | ] 23 | 24 | 25 | describe 'lib/utils/tree', -> 26 | tree = null 27 | 28 | beforeEach -> 29 | tree = sampleTree() 30 | 31 | describe 'TreeUtil.prune(tree, n)', -> 32 | it 'should prune the tree to depth "n"', -> 33 | expect(tree.children[0].children).to.not.be.empty 34 | TreeUtil.prune(tree, 1) 35 | expect(tree.children[0].children).to.be.empty 36 | 37 | describe 'TreeUtil.getSubtree(tree, id)', -> 38 | it 'should return the subtree starting at the node with id "id"', -> 39 | subtree = TreeUtil.getSubtree(tree, 'c2') 40 | expect(subtree.id).to.equal('c2'); 41 | expect(subtree.children).to.be.empty 42 | 43 | describe 'TreeUtil.addNodeWithAncestors(tree, path, node)', -> 44 | it 'should add the node "node" at the path "path", creating necessary ancestors', -> 45 | TreeUtil.addNodeWithAncestors(tree, ['c2', 'c2c1', 'c2c1c1'], name: 'Testing') 46 | expect(tree.children[1].children[0].children[0].id).to.equal('c2c1c1') 47 | 48 | describe 'TreeUtil.calculateValues(tree)', -> 49 | it 'should calculate the values of each node of the tree on the basis of leaf node values', -> 50 | TreeUtil.calculateValues(tree) 51 | expect(tree.value).to.equal(30) 52 | expect(tree.children[0].value).to.equal(10) 53 | 54 | describe 'TreeUtil.getDepth(tree, nodeId)', -> 55 | it 'should calculate the depth of the node with id "nodeId" in the tree "tree"', -> 56 | expect(TreeUtil.getDepth(tree, 'root')).to.equal(0) 57 | expect(TreeUtil.getDepth(tree, 'c2')).to.equal(1) 58 | expect(TreeUtil.getDepth(tree, 'c1c1')).to.equal(2) 59 | -------------------------------------------------------------------------------- /tests/spec/lib/utils/utils.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/utils/utils', -> 2 | describe 'OpenSpending.Utils.formatAmount(amount)', -> 3 | testset = [ 4 | [9000, '9k'] 5 | [9000000, '9m'] 6 | [9000000000, '9bn'] 7 | [-9000, '-9k'] 8 | [-9000000, '-9m'] 9 | ] 10 | 11 | for x in testset 12 | it "should format #{x[0]} as #{x[1]}", -> 13 | expect(OpenSpending.Utils.formatAmount(x[0])).to.equal(x[1]) 14 | 15 | describe 'OpenSpending.Utils.formatAmountWithCommas(amount)', -> 16 | 17 | testset = [ 18 | [9000, '9,000'] 19 | [9000000, '9,000,000'] 20 | [9000000000, '9,000,000,000'] 21 | [-9000, '-9,000'] 22 | [-9000000, '-9,000,000'] 23 | ] 24 | 25 | for x in testset 26 | it "should format #{x[0]} as #{x[1]}", -> 27 | expect(OpenSpending.Utils.formatAmountWithCommas(x[0])).to.equal(x[1]) 28 | 29 | describe 'OpenSpending.Utils.formatAmountWithCommas(amount, 2)', -> 30 | 31 | testset = [ 32 | [9000, '9,000.00'] 33 | [-9000, '-9,000.00'] 34 | ] 35 | 36 | for x in testset 37 | it "should format #{x[0]} as #{x[1]}", -> 38 | expect(OpenSpending.Utils.formatAmountWithCommas(x[0], 2)).to.equal(x[1]) 39 | 40 | 41 | describe 'parseQueryString(qs)', -> 42 | it 'should parse a query string', -> 43 | testdata = 'i=main&mode=front&sid=de8d49b78a85a322c4155015fdce22c4&enc=+Hello%20&empty' 44 | out = parseQueryString(testdata) 45 | exp = [ 46 | ['i', "main"] 47 | ['mode', "front"] 48 | ['sid', "de8d49b78a85a322c4155015fdce22c4"] 49 | ['enc', " Hello "] 50 | ['empty', ""] 51 | ]; 52 | expect(out).to.eql(exp) 53 | 54 | describe 'writeTabularAsHtml({header: [...], data: [...]}, options)', -> 55 | 56 | header = null 57 | data = null 58 | out = null 59 | 60 | beforeEach -> 61 | header = ['column-1', 'column-2'] 62 | data = [ 63 | ['1', 'A'] 64 | ['2', 'b'] 65 | ['3', 'c'] 66 | ] 67 | out = writeTabularAsHtml(header: header, data: data) 68 | 69 | it 'should return an object with "tbody" and "thead" entries', -> 70 | expect(out).to.have.keys(['tbody', 'thead']) 71 | 72 | it 'should write column headers into the "thead" html', -> 73 | expect(out.thead.html()).to.have.string('column-1') 74 | expect(out.thead.html()).to.have.string('column-2') 75 | 76 | it 'should set column names from options.displayNames, if provided', -> 77 | out = writeTabularAsHtml( 78 | {header: header, data: data}, 79 | {displayNames: {'column-2': 'Column 2'}} 80 | ) 81 | expect(out.thead.html()).to.have.string('Column 2') 82 | expect(out.thead.html()).to.not.have.string('column-2') 83 | 84 | it 'should write data into the "tbody" html', -> 85 | res = (x.innerHTML for x in out.tbody.find('td')) 86 | expect(res).to.eql(['1', 'A', '2', 'b', '3', 'c']) 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /tests/spec/lib/widgets.coffee: -------------------------------------------------------------------------------- 1 | describe 'lib/widgets', -> 2 | -------------------------------------------------------------------------------- /tests/stackedbar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 28 | --------------------------------------------------------------------------------