diff --git a/.gitignore b/.gitignore index 1377554..497fbe3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.swp +mup.json +settings.json diff --git a/.meteor/.finished-upgraders b/.meteor/.finished-upgraders new file mode 100644 index 0000000..61ee313 --- /dev/null +++ b/.meteor/.finished-upgraders @@ -0,0 +1,12 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes diff --git a/.meteor/.gitignore b/.meteor/.gitignore new file mode 100644 index 0000000..4083037 --- /dev/null +++ b/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/.meteor/.id b/.meteor/.id new file mode 100644 index 0000000..ead8d92 --- /dev/null +++ b/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +1drptg9f1c9a41wwqeqt diff --git a/.meteor/packages b/.meteor/packages new file mode 100644 index 0000000..5dd1ebb --- /dev/null +++ b/.meteor/packages @@ -0,0 +1,32 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +autopublish +insecure +fourseven:scss +jquery +coffeescript +mquandalle:jade +fortawesome:fontawesome +cunneen:mailgun +meteorhacks:kadira +d3js:d3 +iron:router +standard-minifiers +meteor-base +mobile-experience +mongo +blaze-html-templates +session +tracker +logging +reload +random +ejson +spacebars +check +poetic:materialize-scss +pcel:loading diff --git a/.meteor/platforms b/.meteor/platforms new file mode 100644 index 0000000..efeba1b --- /dev/null +++ b/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/.meteor/release b/.meteor/release new file mode 100644 index 0000000..3a05e0a --- /dev/null +++ b/.meteor/release @@ -0,0 +1 @@ +METEOR@1.2.1 diff --git a/.meteor/versions b/.meteor/versions new file mode 100644 index 0000000..60b5cec --- /dev/null +++ b/.meteor/versions @@ -0,0 +1,87 @@ +autopublish@1.0.4 +autoupdate@1.2.4 +babel-compiler@5.8.24_1 +babel-runtime@0.1.4 +base64@1.0.4 +binary-heap@1.0.4 +blaze@2.1.3 +blaze-html-templates@1.0.1 +blaze-tools@1.0.4 +boilerplate-generator@1.0.4 +caching-compiler@1.0.0 +caching-html-compiler@1.0.2 +callback-hook@1.0.4 +check@1.1.0 +coffeescript@1.0.11 +cunneen:mailgun@0.9.1 +d3js:d3@3.5.8 +ddp@1.2.2 +ddp-client@1.2.1 +ddp-common@1.2.2 +ddp-server@1.2.2 +deps@1.0.9 +diff-sequence@1.0.1 +ecmascript@0.1.6 +ecmascript-runtime@0.2.6 +ejson@1.0.7 +email@1.0.8 +fastclick@1.0.7 +fortawesome:fontawesome@4.4.0 +fourseven:scss@3.4.1 +geojson-utils@1.0.4 +hot-code-push@1.0.0 +html-tools@1.0.5 +htmljs@1.0.5 +http@1.1.1 +id-map@1.0.4 +insecure@1.0.4 +iron:controller@1.0.12 +iron:core@1.0.11 +iron:dynamic-template@1.0.12 +iron:layout@1.0.12 +iron:location@1.0.11 +iron:middleware-stack@1.0.11 +iron:router@1.0.12 +iron:url@1.0.11 +jquery@1.11.4 +launch-screen@1.0.4 +livedata@1.0.15 +localstorage@1.0.5 +logging@1.0.8 +meteor@1.1.10 +meteor-base@1.0.1 +meteorhacks:kadira@2.26.3 +meteorhacks:meteorx@1.4.1 +minifiers@1.1.7 +minimongo@1.0.10 +mobile-experience@1.0.1 +mobile-status-bar@1.0.6 +mongo@1.1.3 +mongo-id@1.0.1 +mongo-livedata@1.0.9 +mquandalle:jade@0.4.5 +mquandalle:jade-compiler@0.4.5 +npm-mongo@1.4.39_1 +observe-sequence@1.0.7 +ordered-dict@1.0.4 +pcel:loading@1.0.3 +poetic:materialize-scss@1.3.5 +promise@0.5.1 +random@1.0.5 +reactive-dict@1.1.3 +reactive-var@1.0.6 +reload@1.1.4 +retry@1.0.4 +routepolicy@1.0.6 +session@1.1.1 +spacebars@1.0.7 +spacebars-compiler@1.0.7 +standard-minifiers@1.0.2 +templating@1.1.5 +templating-tools@1.0.0 +tracker@1.0.9 +ui@1.0.8 +underscore@1.0.4 +url@1.0.5 +webapp@1.2.3 +webapp-hashing@1.0.5 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8fad6c6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,93 @@ +## How to Contribute +In the spirit of open source software, **everyone** is encouraged to help +improve this project. + +### Ways *you* can contribute: +* by [testing the software](http://mauroaperez.com/miamibudget) +* by [using the issue tracker][issue_tracker] for... + * reporting bugs + * suggesting new features + * suggesting labels for our issues +* by improving the code through: + * writing or editing documentation + * writing test specifications + * refactoring the code (**no patch is too small**: fix typos, add comments, + clean up inconsistent whitespace). + * reviewing [open Pull Requests][open_prs] +* by [donating to Code for America][donate] + +### Reporting a bug or other issue +We use the GitHub issue tracker to track bugs and feature +requests. To submit a bug report or feature request: + +1. **[Browse][issue_tracker] or [search][issue_search] our issues** to make +sure your issue hasn't already been submitted. + +2. **[Submit an issue][new_issue]**. +If you're submitting a bug report, it's helpful to include any details that +may be necessary to reproduce the bug, including: + + - a screenshot + - your operating system (Windows 7, Mac OSX 10.9.2, etc.) + - your web browser and version (Internet Explorer 9, Chrome 27, etc.) + - a stack trace of any errors encountered + - your Ruby version (use `ruby -v` from the command line) + +For developers, a bug report should ideally include a pull request with +failing specs. + +### Help Wanted +Some issues in particular we'd be happy if contributors like yourself were +interested in fixing. Browse the issues [labelled `help wanted`][help_wanted] +and see if there's something there that you could fix. + +### Updating the Code? Open a Pull Request +To submit a code change to the project for review by the team: + +1. **Setup:** Make sure you have the [prerequisites installed][prerequisites] +on your computer. + +2. **Fork:** [Fork this repository and clone it on your computer][fork]. + +3. **Install Dependencies:** From the root directory of the app, run `bundle`. + +4. **Branch:** [Create a topic branch][branch] for the one specific issue +you're addressing. + +5. **Write Specs:** Add specs for your unimplemented feature or bug fix in the +`/spec/` directory. + +6. **Test to fail:** + +7. **Implement:** Implement your feature or bug fix. + +8. **Test to pass:** Run `script/test` to run the test suite in addition to the +style checkers. If your specs fail and/or style offenses are reported, return +to **step 7**. + +9. _(If applicable)_ **Clean up JavaScript code:** Run `rake jshint` to check +JavaScript code quality. + +10. **Commit changes:** Add, commit, and push your changes. + +11. **Pull request:** [Submit a pull request][pr] to send your changes to this +repository for review. + +_*If you use Sublime Text, please make sure to set your tab indentation to 2 +spaces. We also highly recommend you use the [TrailingSpaces][trailing_spaces] +plugin and set it to [Trim On Save][trim_on_save]._ + +[install_instructions]: https://github.com/codeforamerica/ohana-web-search/blob/master/INSTALL.md +[open_prs]: https://github.com/Code-for-Miami/miami-budget/pulls +[help_wanted]: https://github.com/Code-for-Miami/miami-budget/labels/help%20wanted +[donate]: http://codeforamerica.org/support-us/ +[issue_tracker]: https://github.com/Code-for-Miami/miami-budget/issues +[issue_search]: https://github.com/Code-for-Miami/miami-budget/search?utf8=%E2%9C%93&q= +[new_issue]: https://github.com/Code-for-Miami/miami-budget/issues/new +[prerequisites]: https://github.com/Code-for-Miami/miami-budget/blob/master/INSTALL.md +[fork]: http://help.github.com/fork-a-repo/ +[branch]: https://help.github.com/articles/creating-and-deleting-branches-within-your-repository +[style_guide]: https://github.com/bbatsov/ruby-style-guide +[pr]: http://help.github.com/send-pull-requests/ +[trailing_spaces]: https://github.com/SublimeText/TrailingSpaces +[trim_on_save]: https://github.com/SublimeText/TrailingSpaces#trim-on-save diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..1f73ddb --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,27 @@ + +# Running Ohana Web Search on your computer + +## Install Prerequisites + +You'll need to have the following software installed and/or referenced for this project: + +- [jQuery][jQuery] +- [D3.js][d3js] +- [Meteor.js][meteorjs] (only used for running the tests) + +[jQuery]: http://jquery.com/download/ +[D3.js]: http://d3js.org/ +[Meteor.js]: https://www.meteor.com/install + +## Installation Instructions + +Clone the `Code for Miami/miami-budget` repository and navigate to the project's directory: + + git clone git@github.com:Code-for-Miami/miami-budget.git + cd miami-budget + +### Run the app +Instructions to be added. The application will run using meteor.js + +### Customize the app +To Be Added diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..38c6bf2 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ab670e --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# Miami Graph + +![Budget Sunburst](http://leadmiami.co/content/images/2015/08/sunburst.png) + +### Experience Miami's Data +Miami Graph started as a single D3.js sunburst visualization of Miami Dade county's 2016 budget proposal data. It aims to make Miami's data more engaging for its citizens. + +[miamigraph.com](http://miamigraph.com) + +**Table of Contents** + +- [Installation](#installation) +- [Contribute](#contribute) + +### Installation + +1. [Install Meteor](https://www.meteor.com/install) +2. `git clone https://github.com/Code-for-Miami/miamigraph.git` +3. From the cloned repo, run `meteor` +4. After the app builds, please visit [http://localhost:3000](http://localhost:3000) + +###Gotcha! +* `Scss compiler error: file to import not found or unreadable: .meteor/.../sass/materialize.scss` + * Ignore this error. Ctrl+C and rerun the app with `meteor` + +### Contribute +* [Trello Task List](https://trello.com/b/fIe4tQWP/miami-graph) +* We meet us at Code for Miami every Monday @7pm @TheLabMiami + +#### Coding +* Fork this repo and clone it on your computer +* Checkout a branch for your work +* Submit a pull request to add your changes + +#### Writing +Refer to Trello + +#### Research +Refer to Trello diff --git a/client/head.jade b/client/head.jade new file mode 100644 index 0000000..375bd9a --- /dev/null +++ b/client/head.jade @@ -0,0 +1,6 @@ +head + meta(http-equiv="Content-Type" content="text/html; charset=UTF-8") + meta(name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no") + title Miami Dade County Budget + + script(src="//cdnjs.cloudflare.com/ajax/libs/numeral.js/1.4.5/numeral.min.js") diff --git a/client/lib/core.js b/client/lib/core.js new file mode 100755 index 0000000..cd5f072 --- /dev/null +++ b/client/lib/core.js @@ -0,0 +1,149 @@ + +// set up main nv object +var nv = window.nv || {}; + +// the major global objects under the nv namespace +nv.dev = false; //set false when in production +nv.tooltip = nv.tooltip || {}; // For the tooltip system +nv.utils = nv.utils || {}; // Utility subsystem +nv.models = nv.models || {}; //stores all the possible models/components +nv.charts = {}; //stores all the ready to use charts +nv.logs = {}; //stores some statistics and potential error messages +nv.dom = {}; //DOM manipulation functions + +nv.dispatch = d3.dispatch('render_start', 'render_end'); + +// Function bind polyfill +// Needed ONLY for phantomJS as it's missing until version 2.0 which is unreleased as of this comment +// https://github.com/ariya/phantomjs/issues/10522 +// http://kangax.github.io/compat-table/es5/#Function.prototype.bind +// phantomJS is used for running the test suite +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + return fBound; + }; +} + +// Development render timers - disabled if dev = false +if (nv.dev) { + nv.dispatch.on('render_start', function(e) { + nv.logs.startTime = +new Date(); + }); + + nv.dispatch.on('render_end', function(e) { + nv.logs.endTime = +new Date(); + nv.logs.totalTime = nv.logs.endTime - nv.logs.startTime; + nv.log('total', nv.logs.totalTime); // used for development, to keep track of graph generation times + }); +} + +// Logs all arguments, and returns the last so you can test things in place +// Note: in IE8 console.log is an object not a function, and if modernizr is used +// then calling Function.prototype.bind with with anything other than a function +// causes a TypeError to be thrown. +nv.log = function() { + if (nv.dev && window.console && console.log && console.log.apply) + console.log.apply(console, arguments); + else if (nv.dev && window.console && typeof console.log == "function" && Function.prototype.bind) { + var log = Function.prototype.bind.call(console.log, console); + log.apply(console, arguments); + } + return arguments[arguments.length - 1]; +}; + +// print console warning, should be used by deprecated functions +nv.deprecated = function(name, info) { + if (console && console.warn) { + console.warn('nvd3 warning: `' + name + '` has been deprecated. ', info || ''); + } +}; + +// The nv.render function is used to queue up chart rendering +// in non-blocking async functions. +// When all queued charts are done rendering, nv.dispatch.render_end is invoked. +nv.render = function render(step) { + // number of graphs to generate in each timeout loop + step = step || 1; + + nv.render.active = true; + nv.dispatch.render_start(); + + var renderLoop = function() { + var chart, graph; + + for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) { + chart = graph.generate(); + if (typeof graph.callback == typeof(Function)) graph.callback(chart); + } + + nv.render.queue.splice(0, i); + + if (nv.render.queue.length) { + setTimeout(renderLoop); + } + else { + nv.dispatch.render_end(); + nv.render.active = false; + } + }; + + setTimeout(renderLoop); +}; + +nv.render.active = false; +nv.render.queue = []; + +/* +Adds a chart to the async rendering queue. This method can take arguments in two forms: +nv.addGraph({ + generate: + callback: +}) + +or + +nv.addGraph(, ) + +The generate function should contain code that creates the NVD3 model, sets options +on it, adds data to an SVG element, and invokes the chart model. The generate function +should return the chart model. See examples/lineChart.html for a usage example. + +The callback function is optional, and it is called when the generate function completes. +*/ +nv.addGraph = function(obj) { + if (typeof arguments[0] === typeof(Function)) { + obj = {generate: arguments[0], callback: arguments[1]}; + } + + nv.render.queue.push(obj); + + if (!nv.render.active) { + nv.render(); + } +}; + +// Node/CommonJS exports +if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') { + module.exports = nv; +} + +if (typeof(window) !== 'undefined') { + window.nv = nv; +} diff --git a/client/lib/masonry.pkgd.min.js b/client/lib/masonry.pkgd.min.js new file mode 100644 index 0000000..628bb12 --- /dev/null +++ b/client/lib/masonry.pkgd.min.js @@ -0,0 +1,9 @@ +/*! + * Masonry PACKAGED v3.2.2 + * Cascading grid layout library + * http://masonry.desandro.com + * MIT License + * by David DeSandro + */ + +!function(a){function b(){}function c(a){function c(b){b.prototype.option||(b.prototype.option=function(b){a.isPlainObject(b)&&(this.options=a.extend(!0,this.options,b))})}function e(b,c){a.fn[b]=function(e){if("string"==typeof e){for(var g=d.call(arguments,1),h=0,i=this.length;i>h;h++){var j=this[h],k=a.data(j,b);if(k)if(a.isFunction(k[e])&&"_"!==e.charAt(0)){var l=k[e].apply(k,g);if(void 0!==l)return l}else f("no such method '"+e+"' for "+b+" instance");else f("cannot call methods on "+b+" prior to initialization; attempted to call '"+e+"'")}return this}return this.each(function(){var d=a.data(this,b);d?(d.option(e),d._init()):(d=new c(this,e),a.data(this,b,d))})}}if(a){var f="undefined"==typeof console?b:function(a){console.error(a)};return a.bridget=function(a,b){c(b),e(a,b)},a.bridget}}var d=Array.prototype.slice;"function"==typeof define&&define.amd?define("jquery-bridget/jquery.bridget",["jquery"],c):c("object"==typeof exports?require("jquery"):a.jQuery)}(window),function(a){function b(b){var c=a.event;return c.target=c.target||c.srcElement||b,c}var c=document.documentElement,d=function(){};c.addEventListener?d=function(a,b,c){a.addEventListener(b,c,!1)}:c.attachEvent&&(d=function(a,c,d){a[c+d]=d.handleEvent?function(){var c=b(a);d.handleEvent.call(d,c)}:function(){var c=b(a);d.call(a,c)},a.attachEvent("on"+c,a[c+d])});var e=function(){};c.removeEventListener?e=function(a,b,c){a.removeEventListener(b,c,!1)}:c.detachEvent&&(e=function(a,b,c){a.detachEvent("on"+b,a[b+c]);try{delete a[b+c]}catch(d){a[b+c]=void 0}});var f={bind:d,unbind:e};"function"==typeof define&&define.amd?define("eventie/eventie",f):"object"==typeof exports?module.exports=f:a.eventie=f}(this),function(a){function b(a){"function"==typeof a&&(b.isReady?a():g.push(a))}function c(a){var c="readystatechange"===a.type&&"complete"!==f.readyState;b.isReady||c||d()}function d(){b.isReady=!0;for(var a=0,c=g.length;c>a;a++){var d=g[a];d()}}function e(e){return"complete"===f.readyState?d():(e.bind(f,"DOMContentLoaded",c),e.bind(f,"readystatechange",c),e.bind(a,"load",c)),b}var f=a.document,g=[];b.isReady=!1,"function"==typeof define&&define.amd?define("doc-ready/doc-ready",["eventie/eventie"],e):"object"==typeof exports?module.exports=e(require("eventie")):a.docReady=e(a.eventie)}(window),function(){function a(){}function b(a,b){for(var c=a.length;c--;)if(a[c].listener===b)return c;return-1}function c(a){return function(){return this[a].apply(this,arguments)}}var d=a.prototype,e=this,f=e.EventEmitter;d.getListeners=function(a){var b,c,d=this._getEvents();if(a instanceof RegExp){b={};for(c in d)d.hasOwnProperty(c)&&a.test(c)&&(b[c]=d[c])}else b=d[a]||(d[a]=[]);return b},d.flattenListeners=function(a){var b,c=[];for(b=0;be;e++)if(b=c[e]+a,"string"==typeof d[b])return b}}var c="Webkit Moz ms Ms O".split(" "),d=document.documentElement.style;"function"==typeof define&&define.amd?define("get-style-property/get-style-property",[],function(){return b}):"object"==typeof exports?module.exports=b:a.getStyleProperty=b}(window),function(a){function b(a){var b=parseFloat(a),c=-1===a.indexOf("%")&&!isNaN(b);return c&&b}function c(){}function d(){for(var a={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},b=0,c=g.length;c>b;b++){var d=g[b];a[d]=0}return a}function e(c){function e(){if(!m){m=!0;var d=a.getComputedStyle;if(j=function(){var a=d?function(a){return d(a,null)}:function(a){return a.currentStyle};return function(b){var c=a(b);return c||f("Style returned "+c+". Are you running this code in a hidden iframe on Firefox? See http://bit.ly/getsizebug1"),c}}(),k=c("boxSizing")){var e=document.createElement("div");e.style.width="200px",e.style.padding="1px 2px 3px 4px",e.style.borderStyle="solid",e.style.borderWidth="1px 2px 3px 4px",e.style[k]="border-box";var g=document.body||document.documentElement;g.appendChild(e);var h=j(e);l=200===b(h.width),g.removeChild(e)}}}function h(a){if(e(),"string"==typeof a&&(a=document.querySelector(a)),a&&"object"==typeof a&&a.nodeType){var c=j(a);if("none"===c.display)return d();var f={};f.width=a.offsetWidth,f.height=a.offsetHeight;for(var h=f.isBorderBox=!(!k||!c[k]||"border-box"!==c[k]),m=0,n=g.length;n>m;m++){var o=g[m],p=c[o];p=i(a,p);var q=parseFloat(p);f[o]=isNaN(q)?0:q}var r=f.paddingLeft+f.paddingRight,s=f.paddingTop+f.paddingBottom,t=f.marginLeft+f.marginRight,u=f.marginTop+f.marginBottom,v=f.borderLeftWidth+f.borderRightWidth,w=f.borderTopWidth+f.borderBottomWidth,x=h&&l,y=b(c.width);y!==!1&&(f.width=y+(x?0:r+v));var z=b(c.height);return z!==!1&&(f.height=z+(x?0:s+w)),f.innerWidth=f.width-(r+v),f.innerHeight=f.height-(s+w),f.outerWidth=f.width+t,f.outerHeight=f.height+u,f}}function i(b,c){if(a.getComputedStyle||-1===c.indexOf("%"))return c;var d=b.style,e=d.left,f=b.runtimeStyle,g=f&&f.left;return g&&(f.left=b.currentStyle.left),d.left=c,c=d.pixelLeft,d.left=e,g&&(f.left=g),c}var j,k,l,m=!1;return h}var f="undefined"==typeof console?c:function(a){console.error(a)},g=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"];"function"==typeof define&&define.amd?define("get-size/get-size",["get-style-property/get-style-property"],e):"object"==typeof exports?module.exports=e(require("desandro-get-style-property")):a.getSize=e(a.getStyleProperty)}(window),function(a){function b(a,b){return a[g](b)}function c(a){if(!a.parentNode){var b=document.createDocumentFragment();b.appendChild(a)}}function d(a,b){c(a);for(var d=a.parentNode.querySelectorAll(b),e=0,f=d.length;f>e;e++)if(d[e]===a)return!0;return!1}function e(a,d){return c(a),b(a,d)}var f,g=function(){if(a.matchesSelector)return"matchesSelector";for(var b=["webkit","moz","ms","o"],c=0,d=b.length;d>c;c++){var e=b[c],f=e+"MatchesSelector";if(a[f])return f}}();if(g){var h=document.createElement("div"),i=b(h,"div");f=i?b:e}else f=d;"function"==typeof define&&define.amd?define("matches-selector/matches-selector",[],function(){return f}):"object"==typeof exports?module.exports=f:window.matchesSelector=f}(Element.prototype),function(a){function b(a,b){for(var c in b)a[c]=b[c];return a}function c(a){for(var b in a)return!1;return b=null,!0}function d(a){return a.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()})}function e(a,e,f){function h(a,b){a&&(this.element=a,this.layout=b,this.position={x:0,y:0},this._create())}var i=f("transition"),j=f("transform"),k=i&&j,l=!!f("perspective"),m={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"otransitionend",transition:"transitionend"}[i],n=["transform","transition","transitionDuration","transitionProperty"],o=function(){for(var a={},b=0,c=n.length;c>b;b++){var d=n[b],e=f(d);e&&e!==d&&(a[d]=e)}return a}();b(h.prototype,a.prototype),h.prototype._create=function(){this._transn={ingProperties:{},clean:{},onEnd:{}},this.css({position:"absolute"})},h.prototype.handleEvent=function(a){var b="on"+a.type;this[b]&&this[b](a)},h.prototype.getSize=function(){this.size=e(this.element)},h.prototype.css=function(a){var b=this.element.style;for(var c in a){var d=o[c]||c;b[d]=a[c]}},h.prototype.getPosition=function(){var a=g(this.element),b=this.layout.options,c=b.isOriginLeft,d=b.isOriginTop,e=parseInt(a[c?"left":"right"],10),f=parseInt(a[d?"top":"bottom"],10);e=isNaN(e)?0:e,f=isNaN(f)?0:f;var h=this.layout.size;e-=c?h.paddingLeft:h.paddingRight,f-=d?h.paddingTop:h.paddingBottom,this.position.x=e,this.position.y=f},h.prototype.layoutPosition=function(){var a=this.layout.size,b=this.layout.options,c={};b.isOriginLeft?(c.left=this.position.x+a.paddingLeft+"px",c.right=""):(c.right=this.position.x+a.paddingRight+"px",c.left=""),b.isOriginTop?(c.top=this.position.y+a.paddingTop+"px",c.bottom=""):(c.bottom=this.position.y+a.paddingBottom+"px",c.top=""),this.css(c),this.emitEvent("layout",[this])};var p=l?function(a,b){return"translate3d("+a+"px, "+b+"px, 0)"}:function(a,b){return"translate("+a+"px, "+b+"px)"};h.prototype._transitionTo=function(a,b){this.getPosition();var c=this.position.x,d=this.position.y,e=parseInt(a,10),f=parseInt(b,10),g=e===this.position.x&&f===this.position.y;if(this.setPosition(a,b),g&&!this.isTransitioning)return void this.layoutPosition();var h=a-c,i=b-d,j={},k=this.layout.options;h=k.isOriginLeft?h:-h,i=k.isOriginTop?i:-i,j.transform=p(h,i),this.transition({to:j,onTransitionEnd:{transform:this.layoutPosition},isCleaning:!0})},h.prototype.goTo=function(a,b){this.setPosition(a,b),this.layoutPosition()},h.prototype.moveTo=k?h.prototype._transitionTo:h.prototype.goTo,h.prototype.setPosition=function(a,b){this.position.x=parseInt(a,10),this.position.y=parseInt(b,10)},h.prototype._nonTransition=function(a){this.css(a.to),a.isCleaning&&this._removeStyles(a.to);for(var b in a.onTransitionEnd)a.onTransitionEnd[b].call(this)},h.prototype._transition=function(a){if(!parseFloat(this.layout.options.transitionDuration))return void this._nonTransition(a);var b=this._transn;for(var c in a.onTransitionEnd)b.onEnd[c]=a.onTransitionEnd[c];for(c in a.to)b.ingProperties[c]=!0,a.isCleaning&&(b.clean[c]=!0);if(a.from){this.css(a.from);var d=this.element.offsetHeight;d=null}this.enableTransition(a.to),this.css(a.to),this.isTransitioning=!0};var q=j&&d(j)+",opacity";h.prototype.enableTransition=function(){this.isTransitioning||(this.css({transitionProperty:q,transitionDuration:this.layout.options.transitionDuration}),this.element.addEventListener(m,this,!1))},h.prototype.transition=h.prototype[i?"_transition":"_nonTransition"],h.prototype.onwebkitTransitionEnd=function(a){this.ontransitionend(a)},h.prototype.onotransitionend=function(a){this.ontransitionend(a)};var r={"-webkit-transform":"transform","-moz-transform":"transform","-o-transform":"transform"};h.prototype.ontransitionend=function(a){if(a.target===this.element){var b=this._transn,d=r[a.propertyName]||a.propertyName;if(delete b.ingProperties[d],c(b.ingProperties)&&this.disableTransition(),d in b.clean&&(this.element.style[a.propertyName]="",delete b.clean[d]),d in b.onEnd){var e=b.onEnd[d];e.call(this),delete b.onEnd[d]}this.emitEvent("transitionEnd",[this])}},h.prototype.disableTransition=function(){this.removeTransitionStyles(),this.element.removeEventListener(m,this,!1),this.isTransitioning=!1},h.prototype._removeStyles=function(a){var b={};for(var c in a)b[c]="";this.css(b)};var s={transitionProperty:"",transitionDuration:""};return h.prototype.removeTransitionStyles=function(){this.css(s)},h.prototype.removeElem=function(){this.element.parentNode.removeChild(this.element),this.emitEvent("remove",[this])},h.prototype.remove=function(){if(!i||!parseFloat(this.layout.options.transitionDuration))return void this.removeElem();var a=this;this.on("transitionEnd",function(){return a.removeElem(),!0}),this.hide()},h.prototype.reveal=function(){delete this.isHidden,this.css({display:""});var a=this.layout.options;this.transition({from:a.hiddenStyle,to:a.visibleStyle,isCleaning:!0})},h.prototype.hide=function(){this.isHidden=!0,this.css({display:""});var a=this.layout.options;this.transition({from:a.visibleStyle,to:a.hiddenStyle,isCleaning:!0,onTransitionEnd:{opacity:function(){this.isHidden&&this.css({display:"none"})}}})},h.prototype.destroy=function(){this.css({position:"",left:"",right:"",top:"",bottom:"",transition:"",transform:""})},h}var f=a.getComputedStyle,g=f?function(a){return f(a,null)}:function(a){return a.currentStyle};"function"==typeof define&&define.amd?define("outlayer/item",["eventEmitter/EventEmitter","get-size/get-size","get-style-property/get-style-property"],e):"object"==typeof exports?module.exports=e(require("wolfy87-eventemitter"),require("get-size"),require("desandro-get-style-property")):(a.Outlayer={},a.Outlayer.Item=e(a.EventEmitter,a.getSize,a.getStyleProperty))}(window),function(a){function b(a,b){for(var c in b)a[c]=b[c];return a}function c(a){return"[object Array]"===l.call(a)}function d(a){var b=[];if(c(a))b=a;else if(a&&"number"==typeof a.length)for(var d=0,e=a.length;e>d;d++)b.push(a[d]);else b.push(a);return b}function e(a,b){var c=n(b,a);-1!==c&&b.splice(c,1)}function f(a){return a.replace(/(.)([A-Z])/g,function(a,b,c){return b+"-"+c}).toLowerCase()}function g(c,g,l,n,o,p){function q(a,c){if("string"==typeof a&&(a=h.querySelector(a)),!a||!m(a))return void(i&&i.error("Bad "+this.constructor.namespace+" element: "+a));this.element=a,this.options=b({},this.constructor.defaults),this.option(c);var d=++r;this.element.outlayerGUID=d,s[d]=this,this._create(),this.options.isInitLayout&&this.layout()}var r=0,s={};return q.namespace="outlayer",q.Item=p,q.defaults={containerStyle:{position:"relative"},isInitLayout:!0,isOriginLeft:!0,isOriginTop:!0,isResizeBound:!0,isResizingContainer:!0,transitionDuration:"0.4s",hiddenStyle:{opacity:0,transform:"scale(0.001)"},visibleStyle:{opacity:1,transform:"scale(1)"}},b(q.prototype,l.prototype),q.prototype.option=function(a){b(this.options,a)},q.prototype._create=function(){this.reloadItems(),this.stamps=[],this.stamp(this.options.stamp),b(this.element.style,this.options.containerStyle),this.options.isResizeBound&&this.bindResize()},q.prototype.reloadItems=function(){this.items=this._itemize(this.element.children)},q.prototype._itemize=function(a){for(var b=this._filterFindItemElements(a),c=this.constructor.Item,d=[],e=0,f=b.length;f>e;e++){var g=b[e],h=new c(g,this);d.push(h)}return d},q.prototype._filterFindItemElements=function(a){a=d(a);for(var b=this.options.itemSelector,c=[],e=0,f=a.length;f>e;e++){var g=a[e];if(m(g))if(b){o(g,b)&&c.push(g);for(var h=g.querySelectorAll(b),i=0,j=h.length;j>i;i++)c.push(h[i])}else c.push(g)}return c},q.prototype.getItemElements=function(){for(var a=[],b=0,c=this.items.length;c>b;b++)a.push(this.items[b].element);return a},q.prototype.layout=function(){this._resetLayout(),this._manageStamps();var a=void 0!==this.options.isLayoutInstant?this.options.isLayoutInstant:!this._isLayoutInited;this.layoutItems(this.items,a),this._isLayoutInited=!0},q.prototype._init=q.prototype.layout,q.prototype._resetLayout=function(){this.getSize()},q.prototype.getSize=function(){this.size=n(this.element)},q.prototype._getMeasurement=function(a,b){var c,d=this.options[a];d?("string"==typeof d?c=this.element.querySelector(d):m(d)&&(c=d),this[a]=c?n(c)[b]:d):this[a]=0},q.prototype.layoutItems=function(a,b){a=this._getItemsForLayout(a),this._layoutItems(a,b),this._postLayout()},q.prototype._getItemsForLayout=function(a){for(var b=[],c=0,d=a.length;d>c;c++){var e=a[c];e.isIgnored||b.push(e)}return b},q.prototype._layoutItems=function(a,b){function c(){d.emitEvent("layoutComplete",[d,a])}var d=this;if(!a||!a.length)return void c();this._itemsOn(a,"layout",c);for(var e=[],f=0,g=a.length;g>f;f++){var h=a[f],i=this._getItemLayoutPosition(h);i.item=h,i.isInstant=b||h.isLayoutInstant,e.push(i)}this._processLayoutQueue(e)},q.prototype._getItemLayoutPosition=function(){return{x:0,y:0}},q.prototype._processLayoutQueue=function(a){for(var b=0,c=a.length;c>b;b++){var d=a[b];this._positionItem(d.item,d.x,d.y,d.isInstant)}},q.prototype._positionItem=function(a,b,c,d){d?a.goTo(b,c):a.moveTo(b,c)},q.prototype._postLayout=function(){this.resizeContainer()},q.prototype.resizeContainer=function(){if(this.options.isResizingContainer){var a=this._getContainerSize();a&&(this._setContainerMeasure(a.width,!0),this._setContainerMeasure(a.height,!1))}},q.prototype._getContainerSize=k,q.prototype._setContainerMeasure=function(a,b){if(void 0!==a){var c=this.size;c.isBorderBox&&(a+=b?c.paddingLeft+c.paddingRight+c.borderLeftWidth+c.borderRightWidth:c.paddingBottom+c.paddingTop+c.borderTopWidth+c.borderBottomWidth),a=Math.max(a,0),this.element.style[b?"width":"height"]=a+"px"}},q.prototype._itemsOn=function(a,b,c){function d(){return e++,e===f&&c.call(g),!0}for(var e=0,f=a.length,g=this,h=0,i=a.length;i>h;h++){var j=a[h];j.on(b,d)}},q.prototype.ignore=function(a){var b=this.getItem(a);b&&(b.isIgnored=!0)},q.prototype.unignore=function(a){var b=this.getItem(a);b&&delete b.isIgnored},q.prototype.stamp=function(a){if(a=this._find(a)){this.stamps=this.stamps.concat(a);for(var b=0,c=a.length;c>b;b++){var d=a[b];this.ignore(d)}}},q.prototype.unstamp=function(a){if(a=this._find(a))for(var b=0,c=a.length;c>b;b++){var d=a[b];e(d,this.stamps),this.unignore(d)}},q.prototype._find=function(a){return a?("string"==typeof a&&(a=this.element.querySelectorAll(a)),a=d(a)):void 0},q.prototype._manageStamps=function(){if(this.stamps&&this.stamps.length){this._getBoundingRect();for(var a=0,b=this.stamps.length;b>a;a++){var c=this.stamps[a];this._manageStamp(c)}}},q.prototype._getBoundingRect=function(){var a=this.element.getBoundingClientRect(),b=this.size;this._boundingRect={left:a.left+b.paddingLeft+b.borderLeftWidth,top:a.top+b.paddingTop+b.borderTopWidth,right:a.right-(b.paddingRight+b.borderRightWidth),bottom:a.bottom-(b.paddingBottom+b.borderBottomWidth)}},q.prototype._manageStamp=k,q.prototype._getElementOffset=function(a){var b=a.getBoundingClientRect(),c=this._boundingRect,d=n(a),e={left:b.left-c.left-d.marginLeft,top:b.top-c.top-d.marginTop,right:c.right-b.right-d.marginRight,bottom:c.bottom-b.bottom-d.marginBottom};return e},q.prototype.handleEvent=function(a){var b="on"+a.type;this[b]&&this[b](a)},q.prototype.bindResize=function(){this.isResizeBound||(c.bind(a,"resize",this),this.isResizeBound=!0)},q.prototype.unbindResize=function(){this.isResizeBound&&c.unbind(a,"resize",this),this.isResizeBound=!1},q.prototype.onresize=function(){function a(){b.resize(),delete b.resizeTimeout}this.resizeTimeout&&clearTimeout(this.resizeTimeout);var b=this;this.resizeTimeout=setTimeout(a,100)},q.prototype.resize=function(){this.isResizeBound&&this.needsResizeLayout()&&this.layout()},q.prototype.needsResizeLayout=function(){var a=n(this.element),b=this.size&&a;return b&&a.innerWidth!==this.size.innerWidth},q.prototype.addItems=function(a){var b=this._itemize(a);return b.length&&(this.items=this.items.concat(b)),b},q.prototype.appended=function(a){var b=this.addItems(a);b.length&&(this.layoutItems(b,!0),this.reveal(b))},q.prototype.prepended=function(a){var b=this._itemize(a);if(b.length){var c=this.items.slice(0);this.items=b.concat(c),this._resetLayout(),this._manageStamps(),this.layoutItems(b,!0),this.reveal(b),this.layoutItems(c)}},q.prototype.reveal=function(a){var b=a&&a.length;if(b)for(var c=0;b>c;c++){var d=a[c];d.reveal()}},q.prototype.hide=function(a){var b=a&&a.length;if(b)for(var c=0;b>c;c++){var d=a[c];d.hide()}},q.prototype.getItem=function(a){for(var b=0,c=this.items.length;c>b;b++){var d=this.items[b];if(d.element===a)return d}},q.prototype.getItems=function(a){if(a&&a.length){for(var b=[],c=0,d=a.length;d>c;c++){var e=a[c],f=this.getItem(e);f&&b.push(f)}return b}},q.prototype.remove=function(a){a=d(a);var b=this.getItems(a);if(b&&b.length){this._itemsOn(b,"remove",function(){this.emitEvent("removeComplete",[this,b])});for(var c=0,f=b.length;f>c;c++){var g=b[c];g.remove(),e(g,this.items)}}},q.prototype.destroy=function(){var a=this.element.style;a.height="",a.position="",a.width="";for(var b=0,c=this.items.length;c>b;b++){var d=this.items[b];d.destroy()}this.unbindResize();var e=this.element.outlayerGUID;delete s[e],delete this.element.outlayerGUID,j&&j.removeData(this.element,this.constructor.namespace)},q.data=function(a){var b=a&&a.outlayerGUID;return b&&s[b]},q.create=function(a,c){function d(){q.apply(this,arguments)}return Object.create?d.prototype=Object.create(q.prototype):b(d.prototype,q.prototype),d.prototype.constructor=d,d.defaults=b({},q.defaults),b(d.defaults,c),d.prototype.settings={},d.namespace=a,d.data=q.data,d.Item=function(){p.apply(this,arguments)},d.Item.prototype=new p,g(function(){for(var b=f(a),c=h.querySelectorAll(".js-"+b),e="data-"+b+"-options",g=0,k=c.length;k>g;g++){var l,m=c[g],n=m.getAttribute(e);try{l=n&&JSON.parse(n)}catch(o){i&&i.error("Error parsing "+e+" on "+m.nodeName.toLowerCase()+(m.id?"#"+m.id:"")+": "+o);continue}var p=new d(m,l);j&&j.data(m,a,p)}}),j&&j.bridget&&j.bridget(a,d),d},q.Item=p,q}var h=a.document,i=a.console,j=a.jQuery,k=function(){},l=Object.prototype.toString,m="function"==typeof HTMLElement||"object"==typeof HTMLElement?function(a){return a instanceof HTMLElement}:function(a){return a&&"object"==typeof a&&1===a.nodeType&&"string"==typeof a.nodeName},n=Array.prototype.indexOf?function(a,b){return a.indexOf(b)}:function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1};"function"==typeof define&&define.amd?define("outlayer/outlayer",["eventie/eventie","doc-ready/doc-ready","eventEmitter/EventEmitter","get-size/get-size","matches-selector/matches-selector","./item"],g):"object"==typeof exports?module.exports=g(require("eventie"),require("doc-ready"),require("wolfy87-eventemitter"),require("get-size"),require("desandro-matches-selector"),require("./item")):a.Outlayer=g(a.eventie,a.docReady,a.EventEmitter,a.getSize,a.matchesSelector,a.Outlayer.Item)}(window),function(a){function b(a,b){var d=a.create("masonry");return d.prototype._resetLayout=function(){this.getSize(),this._getMeasurement("columnWidth","outerWidth"),this._getMeasurement("gutter","outerWidth"),this.measureColumns();var a=this.cols;for(this.colYs=[];a--;)this.colYs.push(0);this.maxY=0},d.prototype.measureColumns=function(){if(this.getContainerWidth(),!this.columnWidth){var a=this.items[0],c=a&&a.element;this.columnWidth=c&&b(c).outerWidth||this.containerWidth}this.columnWidth+=this.gutter,this.cols=Math.floor((this.containerWidth+this.gutter)/this.columnWidth),this.cols=Math.max(this.cols,1)},d.prototype.getContainerWidth=function(){var a=this.options.isFitWidth?this.element.parentNode:this.element,c=b(a);this.containerWidth=c&&c.innerWidth},d.prototype._getItemLayoutPosition=function(a){a.getSize();var b=a.size.outerWidth%this.columnWidth,d=b&&1>b?"round":"ceil",e=Math[d](a.size.outerWidth/this.columnWidth);e=Math.min(e,this.cols);for(var f=this._getColGroup(e),g=Math.min.apply(Math,f),h=c(f,g),i={x:this.columnWidth*h,y:g},j=g+a.size.outerHeight,k=this.cols+1-f.length,l=0;k>l;l++)this.colYs[h+l]=j;return i},d.prototype._getColGroup=function(a){if(2>a)return this.colYs;for(var b=[],c=this.cols+1-a,d=0;c>d;d++){var e=this.colYs.slice(d,d+a);b[d]=Math.max.apply(Math,e)}return b},d.prototype._manageStamp=function(a){var c=b(a),d=this._getElementOffset(a),e=this.options.isOriginLeft?d.left:d.right,f=e+c.outerWidth,g=Math.floor(e/this.columnWidth);g=Math.max(0,g);var h=Math.floor(f/this.columnWidth);h-=f%this.columnWidth?0:1,h=Math.min(this.cols-1,h);for(var i=(this.options.isOriginTop?d.top:d.bottom)+c.outerHeight,j=g;h>=j;j++)this.colYs[j]=Math.max(i,this.colYs[j])},d.prototype._getContainerSize=function(){this.maxY=Math.max.apply(Math,this.colYs);var a={height:this.maxY};return this.options.isFitWidth&&(a.width=this._getContainerFitWidth()),a},d.prototype._getContainerFitWidth=function(){for(var a=0,b=this.cols;--b&&0===this.colYs[b];)a++;return(this.cols-a)*this.columnWidth-this.gutter},d.prototype.needsResizeLayout=function(){var a=this.containerWidth;return this.getContainerWidth(),a!==this.containerWidth},d}var c=Array.prototype.indexOf?function(a,b){return a.indexOf(b)}:function(a,b){for(var c=0,d=a.length;d>c;c++){var e=a[c];if(e===b)return c}return-1};"function"==typeof define&&define.amd?define(["outlayer/outlayer","get-size/get-size"],b):"object"==typeof exports?module.exports=b(require("outlayer"),require("get-size")):a.Masonry=b(a.Outlayer,a.getSize)}(window); \ No newline at end of file diff --git a/client/stylesheets/chart.css b/client/stylesheets/chart.css new file mode 100644 index 0000000..1400fef --- /dev/null +++ b/client/stylesheets/chart.css @@ -0,0 +1,274 @@ +.hidden{ + display: none; +} + +#nvd3-chart { + height: 400px; +} + +/* Custom Stylesheet */ +/** + * + * Made By Joash Pereira + * Thanks for MaterializeCSS.com + */ + +.default_color{background-color: #2196F3 !important} + +.default_color_text{color: #2196F3 !important} + +.icon-block { + padding: 0 15px; +} + +#intro, #work, #team {padding-top: 4rem;} + + +#index-banner { + min-height: 632px; + max-height: 864px; + position: relative; + background-color: #2196F3; +} + +#nav_f{ + box-shadow: none !important; + -webkit-box-shadow:none !important; +} + +.text_h { + padding: 15% 0; + font-size: 6.0em; + line-height: 1.25em; + font-weight: 100; + color:white; +} + +.brand-logo{ + position: absolute; + color: #fff; + display: inline-block; + font-size: 2.1rem; + font-style: normal; + font-weight: 100; + padding: 0; + letter-spacing: 7px; +} + +.text_h2 {font-weight: 100;margin-bottom: 4%; line-height: 4.5rem;} + +.span_h2 {font-weight: 300;color: #2196F3;} + +.text_b{color: #2196F3;} + +.in{font-weight: 400 !important; font-style: normal !important;} + +.promo i { + color: #2196F3; + font-size: 7rem; + display: block; +} +.card-content a {color: #2196F3;} + +.card-content a:hover {color: #2196F3;} + +#work, #team{background: rgb(247, 247, 247);} + +.text_pink{color:#EF9A9A;} + +nav ul a { + font-size: 1.2rem; + color: #FFF; + letter-spacing: 2px; + display: block; + font-weight: 300; + padding: 0px 15px; +} + +.cd-headline.type .cd-words-wrapper { + vertical-align: top; + overflow: hidden; +} + +.cd-headline.type .cd-words-wrapper::after { + /* vertical bar */ + content: ''; + position: absolute; + right: 0; + top: 50%; + bottom: auto; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); + height: 90%; + width: 1px; + background-color: #aebcb9; +} + +.cd-headline.type .cd-words-wrapper.waiting::after { + -webkit-animation: cd-pulse 1s infinite; + -moz-animation: cd-pulse 1s infinite; + animation: cd-pulse 1s infinite; +} +.cd-headline.type .cd-words-wrapper.selected { + background-color: #FFF; +} + +.cd-headline.type .cd-words-wrapper.selected::after { + visibility: hidden; +} + +.cd-headline.type .cd-words-wrapper.selected b { + color: #2196F3; +} + +.cd-headline.type b { + visibility: hidden; +} + +.cd-headline.type b.is-visible { + visibility: visible; +} + +.cd-headline.type i { + position: absolute; + visibility: hidden; +} +.cd-headline.type i.in { + position: relative; + visibility: visible; +} + +@-webkit-keyframes cd-pulse { + 0% { + -webkit-transform: translateY(-50%) scale(1); + opacity: 1; + } + 40% { + -webkit-transform: translateY(-50%) scale(0.9); + opacity: 0; + } + 100% { + -webkit-transform: translateY(-50%) scale(0); + opacity: 0; + } +} +@-moz-keyframes cd-pulse { + 0% { + -moz-transform: translateY(-50%) scale(1); + opacity: 1; + } + 40% { + -moz-transform: translateY(-50%) scale(0.9); + opacity: 0; + } + 100% { + -moz-transform: translateY(-50%) scale(0); + opacity: 0; + } +} + +@keyframes cd-pulse { + 0% { + -webkit-transform: translateY(-50%) scale(1); + -moz-transform: translateY(-50%) scale(1); + -ms-transform: translateY(-50%) scale(1); + -o-transform: translateY(-50%) scale(1); + transform: translateY(-50%) scale(1); + opacity: 1; + } + 40% { + -webkit-transform: translateY(-50%) scale(0.9); + -moz-transform: translateY(-50%) scale(0.9); + -ms-transform: translateY(-50%) scale(0.9); + -o-transform: translateY(-50%) scale(0.9); + transform: translateY(-50%) scale(0.9); + opacity: 0; + } + 100% { + -webkit-transform: translateY(-50%) scale(0); + -moz-transform: translateY(-50%) scale(0); + -ms-transform: translateY(-50%) scale(0); + -o-transform: translateY(-50%) scale(0); + transform: translateY(-50%) scale(0); + opacity: 0; + } +} + + +/* Preloader */ +#preloader { + position: fixed; + top:0; + left:0; + right:0; + bottom:0; + background-color:#fff; /* change if the mask should have another color then white */ + z-index:1200; /* makes sure it stays on top */ +} + +#status { + width:200px; + height:200px; + position:absolute; + left:50%; /* centers the loading animation horizontally one the screen */ + top:50%; /* centers the loading animation vertically one the screen */ + background-image:url(../img/status.gif); /* path to your loading animation */ + background-repeat:no-repeat; + background-position:center; + margin:-100px 0 0 -100px; /* is width and height divided by two */ +} + +@media only screen and (max-width: 480px) { + .text_h { + padding: 4% 0; + font-size: 5em; + font-weight: 100; + color: white; + } +} + +input, textarea { + border-bottom: 1px solid #fff; +} + +nav a.button-collapse { + left: -25px; +} + +.card-avatar .waves-effect { + text-align: center; + margin-top: 20px; +} + +.card-avatar img { + height: 160px; + width: 160px; + border-radius: 75px; +} + +.card-avatar .card-content { + text-align: center; +} + +.card .card-content p { + margin: 15px 0px; +} + +.card-avatar .card-content i { + font-size: 1.5rem; +} + +.card-avatar .card-content .card-title { + line-height: 30px !important; +} + +.parallax-container { + max-height: 400px; +} + +footer.page-footer { + margin-top: 0px !important; +} diff --git a/client/stylesheets/main.scss b/client/stylesheets/main.scss new file mode 100644 index 0000000..2920ad7 --- /dev/null +++ b/client/stylesheets/main.scss @@ -0,0 +1,6 @@ +// If you want to override materialize sass variables you can uncomment the following: +@import "{poetic:materialize-scss}/bower_components/materialize/sass/components/_color.scss"; +//$primary-color: color("blue", "lighten-2"); + +// import main scss file +@import "{poetic:materialize-scss}/bower_components/materialize/sass/materialize.scss"; diff --git a/client/stylesheets/misc.css b/client/stylesheets/misc.css new file mode 100644 index 0000000..3e7d6f8 --- /dev/null +++ b/client/stylesheets/misc.css @@ -0,0 +1,22 @@ +.parallax-container { + min-height: 500px; +} + +.row.tight .col { + padding: 0; +} + +.caption { + position: absolute; + width: 100%; + font-size: 3rem; + font-weight: 300; + background-color: rgba(0,0,0,0.3); + text-align: left; + padding-left: 10px; +} + +.caption a { + color: white; + text-decoration: underline; +} diff --git a/client/stylesheets/pieChart.less b/client/stylesheets/pieChart.less new file mode 100644 index 0000000..1ecab21 --- /dev/null +++ b/client/stylesheets/pieChart.less @@ -0,0 +1,10 @@ +#pieChart{ + text { + font-family: sans-serif; + font-size: 12px; + fill: white; + } + path:hover { + fill: orange; + } +} \ No newline at end of file diff --git a/sequences.css b/client/stylesheets/sequences.css similarity index 67% rename from sequences.css rename to client/stylesheets/sequences.css index 6bbc579..c9d6fce 100644 --- a/sequences.css +++ b/client/stylesheets/sequences.css @@ -1,16 +1,8 @@ -body { - font-family: 'Open Sans', sans-serif; - font-size: 12px; - font-weight: 400; - background-color: #fff; - width: 960px; - height: 700px; - margin-top: 10px; -} - #main { - float: left; - width: 750px; + max-width:750px; + position: relative; + left: 49%; + transform: translateX(-50%); } #sidebar { @@ -21,7 +13,6 @@ body { #sequence { width: 200px; height: 120px; - } #legend { @@ -43,14 +34,19 @@ body { #explanation { position: absolute; - top: 260px; - left: 305px; - width: 140px; text-align: center; color: #666; z-index: -1; } +@media (min-width:600px) { + #explanation { + top: 40%; + left: 40%; + width: 140px; + } +} + #percentage { font-size: 2.5em; } diff --git a/client/templates/appBody.coffee b/client/templates/appBody.coffee new file mode 100644 index 0000000..e8966d8 --- /dev/null +++ b/client/templates/appBody.coffee @@ -0,0 +1,4 @@ +Template.appBody.onRendered(()-> + $(".dropdown-button").dropdown() + $(".button-collapse").sideNav() +) diff --git a/client/templates/appBody.tpl.jade b/client/templates/appBody.tpl.jade new file mode 100644 index 0000000..131fd9e --- /dev/null +++ b/client/templates/appBody.tpl.jade @@ -0,0 +1,60 @@ +.navbar-fixed + nav#nav_f.default_color(role="navigation") + .container + .nav-wrapper + a.flow-text.brand-logo(id="logo-container" href="{{pathFor 'home'}}") Miami Graph + + ul.right.hide-on-med-and-down + li + a.dropdown-button(href="#!" data-activates="graphs-dropdown") Graphs + i.material-icons.right arrow_drop_down + + ul#graphs-dropdown.dropdown-content + li + a(href="{{pathFor 'budget'}}") Budget + li + a(href="{{pathFor 'three-eleven'}}") 311 + + + ul#nav-mobile.side-nav + li + a(href="{{pathFor 'budget'}}") Budget + li + a(href="{{pathFor 'three-eleven'}}") 311 + + a.button-collapse(href="#" data-activates="nav-mobile") + i.mdi-navigation-menu + ++yield + +footer#engage.page-footer.default_color.scrollspy + .container.section + .row.center + .col.s12.white-text + h2.white-text Let's connect + .section.col.s12 + p.flow-text + | Join us every Monday at 7pm at + a.white-text(style="text-decoration:underline" href="http://codeformiami.org/") Code for Miami + | at + a.white-text(style="text-decoration:underline" href="http://thelabmiami.com/") The Lab Miami + .col.s4.m2.offset-m3 +<<<<<<< HEAD + .a.white-text(href="https://www.facebook.com/CodeForMiami?fref=ts") + i.large.fa.fa-facebook-square.white-text + .col.s4.m2 + a.white-text(href="https://twitter.com/CodeForMiami") + i.large.fa.fa-twitter-square.white-text + .col.s4.m2 + a.white-text(href="https://github.com/Code-for-Miami/miami-budget") + i.large.fa.fa-github-square.white-text +======= + a.white-text(href="https://www.facebook.com/CodeForMiami?fref=ts") + i.large.fa.fa-facebook-square.white-text + .col.s4.m2 + a.white-text(href="https://twitter.com/CodeForMiami") + i.large.fa.fa-twitter-square.white-text + .col.s4.m2 + a.white-text(href="https://github.com/Code-for-Miami/miami-budget") + i.large.fa.fa-github-square.white-text +>>>>>>> 311 diff --git a/sequences.js b/client/templates/budget/budget.js similarity index 91% rename from sequences.js rename to client/templates/budget/budget.js index b27aa47..59d7727 100644 --- a/sequences.js +++ b/client/templates/budget/budget.js @@ -1,3 +1,5 @@ +Template.budget.onRendered( function() { + // Dimensions of sunburst. var width = 750; var height = 600; @@ -99,11 +101,14 @@ var colors = { var totalSize = 0; var vis = d3.select("#chart").append("svg:svg") - .attr("width", width) - .attr("height", height) + .attr("width", '100%')//width) + .attr("height", '100%')//height) + .attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height)) + .attr('preserveAspectRatio','xMinYMin') .append("svg:g") .attr("id", "container") - .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); + .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")"); +//.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var partition = d3.layout.partition() .size([2 * Math.PI, radius * radius]) @@ -117,11 +122,10 @@ var arc = d3.svg.arc() // Use d3.text and d3.csv.parseRows so that we do not need to have a header // row, and can receive the csv as an array of arrays. -var d3_data = encodeURI($('#data').val()); +//var d3_data = encodeURI($('#data').val()); d3.text( 'operating_budget.csv', //'data://'+d3_data, //"mfp1.csv", // "visit-sequences.csv", function(text) { var csv = d3.csv.parseRows(text); - print_csv = csv; var json = buildHierarchy(csv); createVisualization(json); }); @@ -131,9 +135,8 @@ function createVisualization(json) { // Basic setup of page elements. initializeBreadcrumbTrail(); - drawLegend(); - d3.select("#togglelegend").on("click", toggleLegend); - toggleLegend(); + //drawLegend(); + //toggleLegend(); // Bounding circle underneath the sunburst, to make it easier to detect // when the mouse leaves the parent g. @@ -191,7 +194,11 @@ function mouseover(d) { .text(percentageString); d3.select("#explanation") - .style("visibility", ""); + .style("visibility", "") + .attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height)) + .attr('preserveAspectRatio','xMinYMin') + .attr("id", "explanation") + .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")"); var sequenceArray = getAncestors(d); updateBreadcrumbs(sequenceArray, percentageString); @@ -246,9 +253,12 @@ function getAncestors(node) { function initializeBreadcrumbTrail() { // Add the svg area. var trail = d3.select("#sequence").append("svg:svg") - .attr("width", width) - .attr("height", 150) - .attr("id", "trail"); + .attr("width", 300) + .attr("height", 150) + //.attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height)) + //.attr('preserveAspectRatio','xMinYMin') + .attr("id", "trail") + .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")"); // Add the label at the end, for the percentage. trail.append("svg:text") .attr("id", "endlabel") @@ -399,3 +409,5 @@ function buildHierarchy(csv) { } return root; }; + +}); diff --git a/client/templates/budget/budget.tpl.jade b/client/templates/budget/budget.tpl.jade new file mode 100644 index 0000000..24524a7 --- /dev/null +++ b/client/templates/budget/budget.tpl.jade @@ -0,0 +1,18 @@ +.section.container + // Hero + .section.scrollspy#visual + .container + .row + .col.s12 + h2.center.header.text_h2 + | See Miami Dade's 2016 + a(href="https://transparencyapps.demo.socrata.com/dataset/Miami-Dade-FY-16-Proposed-Operating-Budget/un64-wacr?") budget proposal. + #main.col.s12 + #chart + #explanation(style="visibility: hidden;") + span#value + br + span#percentage + br + of total budget + #sequence diff --git a/client/templates/graph/graph.tpl.jade b/client/templates/graph/graph.tpl.jade new file mode 100644 index 0000000..089bf14 --- /dev/null +++ b/client/templates/graph/graph.tpl.jade @@ -0,0 +1,4 @@ +.section + .container + .row + +pieChart diff --git a/client/templates/home/home.coffee b/client/templates/home/home.coffee new file mode 100644 index 0000000..3586ffc --- /dev/null +++ b/client/templates/home/home.coffee @@ -0,0 +1,3 @@ +Template.home.onRendered(()-> + $('.parallax').parallax() +) diff --git a/client/templates/home/home.tpl.jade b/client/templates/home/home.tpl.jade new file mode 100644 index 0000000..64824d1 --- /dev/null +++ b/client/templates/home/home.tpl.jade @@ -0,0 +1,14 @@ +.row.center.tight + .col.s12 + span.caption + a(href="{{pathFor 'three-eleven' }}") 311 Calls + iframe(width="100%" height="520" frameborder="0" src="https://miamigraph.cartodb.com/viz/c761ed3e-8bb0-11e5-a9cf-0ecfd53eb7d3/embed_map" allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen) + + .col.s12.parallax-container.valign-wrapper + .row.center.valign + h1.text_h2 We visualize city data + + .col.s12 + span.caption + a(href="{{pathFor 'budget' }}") 2016 Budget + iframe(width="100%" height="350" frameborder="0" src="{{pathFor 'sunburst' }}" allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen) diff --git a/client/templates/no-layout.tpl.jade b/client/templates/no-layout.tpl.jade new file mode 100644 index 0000000..382e6d3 --- /dev/null +++ b/client/templates/no-layout.tpl.jade @@ -0,0 +1 @@ ++yield diff --git a/client/templates/pie/form.tpl.jade b/client/templates/pie/form.tpl.jade new file mode 100644 index 0000000..0bfc7d9 --- /dev/null +++ b/client/templates/pie/form.tpl.jade @@ -0,0 +1,73 @@ +.navbar-fixed + nav#nav_f.default_color(role="navigation") + .container + .nav-wrapper + a.flow-text.brand-logo(id="logo-container" href="#{pathFor 'home' }") Miami Graph + + // Menu hidden till nav pages are created + + //ul.right.hide-on-med-and-down + li + a(href="#{pathFor 'about'}") About + + //ul#nav-mobile.side-nav + li + a(href="#{pathFor 'about'}") About + + a.button-collapse.grey-text(href="#" data-activates="nav-mobile") + i.mdi-navigation-menu + +// Hero +.section.scrollspy#game + .container + .row.center + p.flow-text How would you build a budget for Miami? + p.flow-text Sort each slice from highest slice to lowest + p.flow-text Drag the bar to fine-tune + p.flow-text Hover over blah for more details + .row + .col.m6 + each slices + .budget-item.row(id="#{key}") + .row + .col.s2 + .row + button.raise-priority.btn-floating + i.fa.fa-lg.fa-arrow-up + .row + button.lower-priority.btn-floating + i.fa.fa-lg.fa-arrow-down + .col.s9 + .row + .col.s7 + a(href="#") + h5.budget-label #{label} + .col.s5 + h6.dollar-amt #{dollars} + .row + input.validate(type="range" value="#{value}" min="0" max="100" step="1") + .col.m6 + .row + +pieChart + .row + h4.center Sweet sweet lemonade + p.flow-text Sweet marshmallow icing soufflé donut icing sweet soufflé caramels. Chupa chups cheesecake chocolate cake. Icing biscuit bear claw bonbon. + .row.center + button#submit-graph.btn Submit + + #results.row.hidden + +pieResults + + +footer#engage.page-footer.default_color.scrollspy + .container.section + .row.center + .col.s4.m2.offset-m3 + a.white-text(href="https://www.facebook.com/CodeForMiami?fref=ts") + i.large.fa.fa-facebook-square.white-text + .col.s4.m2 + a.white-text(href="https://twitter.com/CodeForMiami") + i.large.fa.fa-twitter-square.white-text + .col.s4.m2 + a.white-text(href="https://github.com/Code-for-Miami/miami-budget") + i.large.fa.fa-github-square.white-text diff --git a/client/templates/pie/pieChart.js b/client/templates/pie/pieChart.js new file mode 100644 index 0000000..8f3a186 --- /dev/null +++ b/client/templates/pie/pieChart.js @@ -0,0 +1,231 @@ +var Slices = new Meteor.Collection(null); +Session.setDefault('pieChartSort','none'); +Session.setDefault('pieChartSortModifier',undefined); + +Template.pieResults.helpers({ + slice: function() { + return Slices.find(); + }, + numSlices: function() { + return BuiltBudgets.find().count(); + }, + sliceAvg: function(){ + console.log(this.key); + return getAvg(BuiltBudgets.find().fetch(), this.key); + } +}); + +totalBudget = 100; + +getAvg = function(budgets, key){ + var sum = 0; + for (var i=0; i 0.005); // 0.005 radians = 0.29 degrees + }); + + var path = vis.data([json]).selectAll("path") + .data(nodes) + .enter().append("svg:path") + .attr("display", function(d) { return d.depth ? null : "none"; }) + .attr("d", arc) + .attr("fill-rule", "evenodd") + .style("fill", function(d) { + if (colors.hasOwnProperty(d.name)) { + return colors[d.name]; + } else { + return colors.default; + } + }) + .style("opacity", 1) + .on("mouseover", mouseover); + + // Add the mouseleave handler to the bounding circle. + d3.select("#container").on("mouseleave", mouseleave); + + // Get total size of the tree = value of root node from partition. + totalSize = path.node().__data__.value; + }; + +// Fade all but the current sequence, and show it in the breadcrumb trail. +function mouseover(d) { + + var percentage = (100 * d.value / totalSize).toPrecision(3); + var percentageString = percentage + "%"; + if (percentage < 0.1) { + percentageString = "< 0.1%"; + } + + d3.select('#value') + .text("$"+numeral(d.value).format('0,0')); + + d3.select("#percentage") + .text(percentageString); + + d3.select("#explanation") + .style("visibility", "") + .attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height)) + .attr('preserveAspectRatio','xMinYMin') + .attr("id", "explanation") + .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")"); + + var sequenceArray = getAncestors(d); + updateBreadcrumbs(sequenceArray, percentageString); + + // Fade all the segments. + d3.selectAll("path") + .style("opacity", 0.3); + + // Then highlight only those that are an ancestor of the current segment. + vis.selectAll("path") + .filter(function(node) { + return (sequenceArray.indexOf(node) >= 0); + }) + .style("opacity", 1); +} + +// Restore everything to full opacity when moving off the visualization. +function mouseleave(d) { + + // Hide the breadcrumb trail + d3.select("#trail") + .style("visibility", "hidden"); + + // Deactivate all segments during transition. + d3.selectAll("path").on("mouseover", null); + + // Transition each segment to full opacity and then reactivate it. + d3.selectAll("path") + .transition() + .duration(1000) + .style("opacity", 1) + .each("end", function() { + d3.select(this).on("mouseover", mouseover); + }); + + d3.select("#explanation") + .style("visibility", "hidden"); +} + +// Given a node in a partition layout, return an array of all of its ancestor +// nodes, highest first, but excluding the root. +function getAncestors(node) { + var path = []; + var current = node; + while (current.parent) { + path.unshift(current); + current = current.parent; + } + return path; +} + +function initializeBreadcrumbTrail() { + // Add the svg area. + var trail = d3.select("#sequence").append("svg:svg") + .attr("width", 300) + .attr("height", 150) + //.attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height)) + //.attr('preserveAspectRatio','xMinYMin') + .attr("id", "trail") + .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")"); + // Add the label at the end, for the percentage. + trail.append("svg:text") + .attr("id", "endlabel") + .style("fill", "#000"); +} + +// Generate a string that describes the points of a breadcrumb polygon. +function breadcrumbPoints(d, i) { + var points = []; + points.push("0,0"); + points.push(b.w + ",0"); + points.push(b.w + b.t + "," + (b.h / 2)); + points.push(b.w + "," + b.h); + points.push("0," + b.h); + if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex. + points.push(b.t + "," + (b.h / 2)); + } + return points.join(" "); +} + +// Update the breadcrumb trail to show the current sequence and percentage. +function updateBreadcrumbs(nodeArray, percentageString) { + + // Data join; key function combines name and depth (= position in sequence). + var g = d3.select("#trail") + .selectAll("g") + .data(nodeArray, function(d) { return d.name + d.depth; }); + + // Add breadcrumb and label for entering nodes. + var entering = g.enter().append("svg:g"); + + entering.append("svg:polygon") + .attr("points", breadcrumbPoints) + .style("fill", 'transparent');//function(d) { return colors[d.name]; }); + + entering.append("svg:text") + .attr("x", 10)//(b.w + b.t) / 2) + .attr("y", b.h / 2) + .attr("dy", "0.35em") + .attr("text-anchor", "left") + .text(function(d) { return d.name; }); + + // Set position for entering and updating nodes. + g.attr("transform", function(d, i) { + return "translate(-10, " + i*20 + ")";// * (b.w + b.s) + ", 0)"; + }); + + // Remove exiting nodes. + g.exit().remove(); + + // Now move and update the percentage at the end. + /* d3.select("#trail").select("#endlabel") + .attr("x", 0)//(nodeArray.length + 0.5) * (b.w + b.s)) + .attr("y", b.h / 2) + .attr("dy", "0.35em") + //.attr("text-anchor", "middle") + .text(percentageString); + */ + + // Make the breadcrumb trail visible, if it's hidden. + d3.select("#trail") + .style("visibility", ""); + +} + +function drawLegend() { + + // Dimensions of legend item: width, height, spacing, radius of rounded rect. + var li = { + w: 75, h: 30, s: 3, r: 3 + }; + + var legend = d3.select("#legend").append("svg:svg") + .attr("width", li.w) + .attr("height", d3.keys(colors).length * (li.h + li.s)); + + var g = legend.selectAll("g") + .data(d3.entries(colors)) + .enter().append("svg:g") + .attr("transform", function(d, i) { + return "translate(0," + i * (li.h + li.s) + ")"; + }); + + g.append("svg:rect") + .attr("rx", li.r) + .attr("ry", li.r) + .attr("width", li.w) + .attr("height", li.h) + .style("fill", function(d) { return d.value; }); + + g.append("svg:text") + .attr("x", li.w / 2) + .attr("y", li.h / 2) + .attr("dy", "0.35em") + // .attr("text-anchor", "middle") + .text(function(d) { return d.key; }); +} + +function toggleLegend() { + var legend = d3.select("#legend"); + if (legend.style("visibility") == "hidden") { + legend.style("visibility", ""); + } else { + legend.style("visibility", "hidden"); + } +} + +// Take a 2-column CSV and transform it into a hierarchical structure suitable +// for a partition layout. The first column is a sequence of step names, from +// root to leaf, separated by hyphens. The second column is a count of how +// often that sequence occurred. +function buildHierarchy(csv) { + var root = {"name": "root", "children": []}; + for (var i = 0; i < csv.length; i++) { + //var sequence = csv[i][0]; + var size = +csv[i][3]; + if (isNaN(size)) { // e.g. if this is a header row + continue; + } + var parts = [csv[i][1], csv[i][2], csv[i][0]];//sequence.split("-"); + var currentNode = root; + for (var j = 0; j < parts.length; j++) { + var children = currentNode["children"]; + var nodeName = parts[j]; + var childNode; + if (j + 1 < parts.length) { + // Not yet at the end of the sequence; move down the tree. + var foundChild = false; + for (var k = 0; k < children.length; k++) { + if (children[k]["name"] == nodeName) { + childNode = children[k]; + foundChild = true; + break; + } + } + // If we don't already have a child node for this branch, create it. + if (!foundChild) { + childNode = {"name": nodeName, "children": []}; + children.push(childNode); + } + currentNode = childNode; + } else { + // Reached the end of the sequence; create a leaf node. + childNode = {"name": nodeName, "size": size}; + children.push(childNode); + } + } + } + return root; +}; + +}); diff --git a/client/templates/sunburst/sunburst.tpl.jade b/client/templates/sunburst/sunburst.tpl.jade new file mode 100644 index 0000000..90acf29 --- /dev/null +++ b/client/templates/sunburst/sunburst.tpl.jade @@ -0,0 +1,14 @@ +#main + #chart + #explanation(style="visibility: hidden;") + span#value + br + span#percentage + br + of total budget + #sequence +#sidebar + input#togglelegend(type="checkbox" checked="checked") + | Legend + br + #legend(style="visibility: hidden;") diff --git a/client/templates/three-eleven/threeEleven.tpl.jade b/client/templates/three-eleven/threeEleven.tpl.jade new file mode 100644 index 0000000..ccc5615 --- /dev/null +++ b/client/templates/three-eleven/threeEleven.tpl.jade @@ -0,0 +1,6 @@ +.grey.lighten-5 + .row + .col.s12 + .row.center.valign-wrapper(style="height:500px") + h2.header.text_h2.valign See how 311 receives 800+ calls in one day + iframe(width="100%" height="520" frameborder="0" src="https://miamigraph.cartodb.com/viz/c761ed3e-8bb0-11e5-a9cf-0ecfd53eb7d3/embed_map" allowfullscreen webkitallowfullscreen mozallowfullscreen oallowfullscreen msallowfullscreen) diff --git a/index.html b/index.html deleted file mode 100644 index 61a8f6f..0000000 --- a/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Sequences sunburst - - - - - -
-
- -
-
- - - - - - - - - diff --git a/lib/collections.js b/lib/collections.js new file mode 100644 index 0000000..ee71f79 --- /dev/null +++ b/lib/collections.js @@ -0,0 +1,2 @@ +//Slices = new Meteor.Collection('slices') +BuiltBudgets = new Meteor.Collection('builtBudgets') diff --git a/lib/methods.coffee b/lib/methods.coffee new file mode 100644 index 0000000..7b5852c --- /dev/null +++ b/lib/methods.coffee @@ -0,0 +1,9 @@ +Meteor.methods( + submitGraph: (slices)-> + budget = {} + budget[slice.key] = parseInt(slice.value) for slice in slices + BuiltBudgets.insert(budget) + + resetBuiltBudgets: ()-> + BuiltBudgets.remove({}) +) diff --git a/lib/router.coffee b/lib/router.coffee new file mode 100644 index 0000000..ed0a868 --- /dev/null +++ b/lib/router.coffee @@ -0,0 +1,24 @@ +Router.configure( + layoutTemplate: 'appBody' + waitOn: ()-> + return [ + Meteor.subscribe('builtBudgets') + ] +) + +Router.route('/', () -> + this.render('home') + , + name: 'home' +) + +Router.route('sunburst', ()-> + this.layout 'no-layout' + this.render() +) +Router.route('budget-builder', ()-> + this.render('form') +) +Router.route('pie') +Router.route('three-eleven') +Router.route('budget') diff --git a/public/._miamigraph b/public/._miamigraph new file mode 100755 index 0000000..368200d Binary files /dev/null and b/public/._miamigraph differ diff --git a/public/311_calls.png b/public/311_calls.png new file mode 100644 index 0000000..b1e0705 Binary files /dev/null and b/public/311_calls.png differ diff --git a/public/budget_graph.png b/public/budget_graph.png new file mode 100644 index 0000000..c106c49 Binary files /dev/null and b/public/budget_graph.png differ diff --git a/operating_budget.csv b/public/operating_budget.csv similarity index 100% rename from operating_budget.csv rename to public/operating_budget.csv diff --git a/server/publish.coffee b/server/publish.coffee new file mode 100644 index 0000000..d282448 --- /dev/null +++ b/server/publish.coffee @@ -0,0 +1,6 @@ +Meteor.publish('slices', ()-> + # return Slices.find() +) +Meteor.publish('builtBudgets', ()-> + return BuiltBudgets.find() +) diff --git a/server/smtp.coffee b/server/smtp.coffee new file mode 100644 index 0000000..9928dd6 --- /dev/null +++ b/server/smtp.coffee @@ -0,0 +1,23 @@ +Meteor.startup ( -> + Meteor.Mailgun.config( + username: 'postmaster@mptysquare.com' + password: '41ffcd0bf5d282d3f0ff516e138db78b' + ) +) + +Meteor.methods( + sendEmail: (field) -> + + check([field.to, field.from, field.subject, field.text, field.html], [String]) + + this.unblock() + + Meteor.Mailgun.send({ + to: field.to + from: field.from + subject: field.subject + text: field.text + html: field.html + }) + console.log('email sent') +)