├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── README.md ├── app ├── .htaccess ├── 404.html ├── data │ └── sample-data.json ├── demos │ ├── tutorial1.csv │ └── tutorial2.tsv ├── images │ ├── C.png │ ├── cumulativeLineChart.png │ ├── discreteBarChart.png │ ├── donutChart.png │ ├── highcharts.png │ ├── historicalBarChart.png │ ├── lineChart.png │ ├── map.png │ ├── multiBarChart.png │ ├── multiBarHorizontalChart.png │ ├── pieChart.png │ ├── scatterChart.png │ ├── stackedAreaChart.png │ └── tutorial1-requirement.png ├── index.html ├── partials │ ├── about.html │ ├── chartbuilder.html │ ├── data-forms │ │ ├── edit-in-place.html │ │ ├── live-data-table.html │ │ └── structure-data-input.html │ ├── faq.html │ ├── home.html │ └── tutorials.html ├── robots.txt ├── scripts │ ├── angular_modules │ │ ├── chartbuilder-options │ │ │ ├── options-constants.js │ │ │ ├── options.html │ │ │ └── options.js │ │ ├── datamaps │ │ │ ├── angular-datamaps.js │ │ │ ├── data.js │ │ │ └── main.js │ │ ├── highcharts │ │ │ ├── data.js │ │ │ └── main.js │ │ ├── nvd3-modules │ │ │ ├── angular-nvd3.js │ │ │ ├── chartbuilderNvd3.js │ │ │ ├── cumulativeLineChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── discreteBarChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── historicalBarChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── lineChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── lineWithFocusChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── multiBarChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── multiBarHorizontalChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── pieChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ │ ├── scatterChart │ │ │ │ └── main.js │ │ │ ├── scatterPlusLineChart │ │ │ │ └── main.js │ │ │ └── stackedAreaChart │ │ │ │ ├── data.js │ │ │ │ └── main.js │ │ └── ui-sortable │ │ │ └── sortable.js │ ├── controllers │ │ └── controllers.js │ ├── directives │ │ ├── bsAffix.js │ │ ├── colors.js │ │ ├── data-input.js │ │ ├── directives.js │ │ ├── edit-in-place.js │ │ ├── input-group.js │ │ ├── live-data-table.js │ │ ├── module.js │ │ ├── save-images.js │ │ └── template-loader.js │ ├── filters │ │ └── filters.js │ ├── main.js │ └── services │ │ └── services.js └── styles │ ├── _animations.scss │ ├── _charts.scss │ ├── _color-picker.scss │ ├── _custom_mixins.scss │ ├── _editinplace.scss │ ├── _home.scss │ ├── _navbar.scss │ ├── _options.scss │ ├── _sidebar.scss │ ├── _spectrum.scss │ ├── style.css │ └── style.scss ├── bower.json ├── config ├── karma.conf.js └── webpack.config.js ├── dist ├── images │ ├── C.png │ ├── cumulativeLineChart.png │ ├── discreteBarChart.png │ ├── donutChart.png │ ├── highcharts.png │ ├── historicalBarChart.png │ ├── lineChart.png │ ├── map.png │ ├── multiBarChart.png │ ├── multiBarHorizontalChart.png │ ├── pieChart.png │ ├── scatterChart.png │ ├── stackedAreaChart.png │ └── tutorial1-requirement.png ├── index.html ├── robots.txt ├── scripts │ ├── chartbuilder-ui.js │ ├── main.bundle.js │ └── main.bundle.min.js └── styles │ └── style.css ├── package.json ├── tasks ├── aliases.json ├── autoprefixer.json ├── buildcontrol.json ├── clean.json ├── compass.json ├── concat.json ├── concurrent.json ├── connect.json ├── copy.json ├── htmlmin.json ├── imagemin.json ├── jshint.js ├── svgmin.json ├── usemin.json ├── useminPrepare.json ├── watch.json ├── webpack.js └── yeoman.json ├── test ├── specs │ ├── angularInjectionSpec.js │ └── loadingSpec.js └── test-main.js └── ui ├── _chartbuilder-options.js └── chart.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | .tmp 3 | node_modules/ 4 | bower_components/ 5 | *.DS_Store -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "jquery": true, 21 | "globals": { 22 | "define": true, 23 | "requirejs": true, 24 | "_": true, 25 | "angular": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | var path = require('path'); 3 | 4 | require('load-grunt-config')(grunt, { 5 | // path to task.js files 6 | configPath: path.join(process.cwd(), 'tasks') 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angularjs-d3-chartbuilder 2 | 3 | ## Installation 4 | 5 | 1. clone this repository 6 | 1. `cd $path/angularjs-d3-chartbuilder` 7 | 1. `npm install` 8 | 1. `bower install` 9 | 10 | Then run `grunt serve` which will autoload the app in your default browser. 11 | 12 | ## Building vizualization modules 13 | 14 | stub 15 | 16 | ## Embedding 17 | 18 | ### In WordPress 19 | 20 | A plugin for WordPress can be found at http://github.com/alleyinteractive/wordpress-chartbuilder. Follow the instructions to install. You can create new charts and embed them in posts from your WordPress admin. 21 | 22 | ### With the embed script 23 | 24 | If you'd just like to embed a single chart, you can use the included inline embed script by pasting this into your html after replacing the two data attributes with the text you saved from chartbuilder. 25 | 26 | 32 | 33 | -------------------------------------------------------------------------------- /app/404.html: -------------------------------------------------------------------------------- 1 |

Not found 134 | :(

Sorry, but the page you were trying 135 | to view does not exist.

It looks like this was the result 136 | of either:

138 | -------------------------------------------------------------------------------- /app/data/sample-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "discrete-bar-chart": [{ 3 | "key": "Cumulative Return", 4 | "values": [ 5 | ["A", -29.765957771107 ], 6 | ["B" , 0 ], 7 | ["C" , 32.807804682612 ], 8 | ["D" , 196.45946739256 ], 9 | ["E" , 0.19434030906893 ], 10 | ["F" , -98.079782601442 ], 11 | ["G" , -13.925743130903 ], 12 | ["H" , -5.1387322875705 ] 13 | ] 14 | }], 15 | "line-chart": [{ 16 | "key": "Series 1", 17 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , -6.3382185140371] , [ 1030766400000 , -5.9507873460847] , [ 1033358400000 , -11.569146943813] , [ 1036040400000 , -5.4767332317425] , [ 1038632400000 , 0.50794682203014] , [ 1041310800000 , -5.5310285460542] , [ 1043989200000 , -5.7838296963382] , [ 1046408400000 , -7.3249341615649] , [ 1049086800000 , -6.7078630712489] , [ 1051675200000 , 0.44227126150934] , [ 1054353600000 , 7.2481659343222] , [ 1056945600000 , 9.2512381306992] , [ 1059624000000 , 11.341210982529] , [ 1062302400000 , 14.734820409020] , [ 1064894400000 , 12.387148007542] , [ 1067576400000 , 18.436471461827] , [ 1070168400000 , 19.830742266977] , [ 1072846800000 , 22.643205829887] , [ 1075525200000 , 26.743156781239] , [ 1078030800000 , 29.597478802228] , [ 1080709200000 , 30.831697585341] , [ 1083297600000 , 28.054068024708] , [ 1085976000000 , 29.294079423832] , [ 1088568000000 , 30.269264061274] , [ 1091246400000 , 24.934526898906] , [ 1093924800000 , 24.265982759406] , [ 1096516800000 , 27.217794897473] , [ 1099195200000 , 30.802601992077] , [ 1101790800000 , 36.331003758254] , [ 1104469200000 , 43.142498700060] , [ 1107147600000 , 40.558263931958] , [ 1109566800000 , 42.543622385800] , [ 1112245200000 , 41.683584710331] , [ 1114833600000 , 36.375367302328] , [ 1117512000000 , 40.719688980730] , [ 1120104000000 , 43.897963036919] , [ 1122782400000 , 49.797033975368] , [ 1125460800000 , 47.085993935989] , [ 1128052800000 , 46.601972859745] , [ 1130734800000 , 41.567784572762] , [ 1133326800000 , 47.296923737245] , [ 1136005200000 , 47.642969612080] , [ 1138683600000 , 50.781515820954] , [ 1141102800000 , 52.600229204305] , [ 1143781200000 , 55.599684490628] , [ 1146369600000 , 57.920388436633] , [ 1149048000000 , 53.503593218971] , [ 1151640000000 , 53.522973979964] , [ 1154318400000 , 49.846822298548] , [ 1156996800000 , 54.721341614650] , [ 1159588800000 , 58.186236223191] , [ 1162270800000 , 63.908065540997] , [ 1164862800000 , 69.767285129367] , [ 1167541200000 , 72.534013373592] , [ 1170219600000 , 77.991819436573] , [ 1172638800000 , 78.143584404990] , [ 1175313600000 , 83.702398665233] , [ 1177905600000 , 91.140859312418] , [ 1180584000000 , 98.590960607028] , [ 1183176000000 , 96.245634754228] , [ 1185854400000 , 92.326364432615] , [ 1188532800000 , 97.068765332230] , [ 1191124800000 , 105.81025556260] , [ 1193803200000 , 114.38348777791] , [ 1196398800000 , 103.59604949810] , [ 1199077200000 , 101.72488429307] , [ 1201755600000 , 89.840147735028] , [ 1204261200000 , 86.963597532664] , [ 1206936000000 , 84.075505208491] , [ 1209528000000 , 93.170105645831] , [ 1212206400000 , 103.62838083121] , [ 1214798400000 , 87.458241365091] , [ 1217476800000 , 85.808374141319] , [ 1220155200000 , 93.158054469193] , [ 1222747200000 , 65.973252382360] , [ 1225425600000 , 44.580686638224] , [ 1228021200000 , 36.418977140128] , [ 1230699600000 , 38.727678144761] , [ 1233378000000 , 36.692674173387] , [ 1235797200000 , 30.033022809480] , [ 1238472000000 , 36.707532162718] , [ 1241064000000 , 52.191457688389] , [ 1243742400000 , 56.357883979735] , [ 1246334400000 , 57.629002180305] , [ 1249012800000 , 66.650985790166] , [ 1251691200000 , 70.839243432186] , [ 1254283200000 , 78.731998491499] , [ 1256961600000 , 72.375528540349] , [ 1259557200000 , 81.738387881630] , [ 1262235600000 , 87.539792394232] , [ 1264914000000 , 84.320762662273] , [ 1267333200000 , 90.621278391889] , [ 1270008000000 , 102.47144881651] , [ 1272600000000 , 102.79320353429] , [ 1275278400000 , 90.529736050479] , [ 1277870400000 , 76.580859994531] , [ 1280548800000 , 86.548979376972] , [ 1283227200000 , 81.879653334089] , [ 1285819200000 , 101.72550015956] , [ 1288497600000 , 107.97964852260] , [ 1291093200000 , 106.16240630785] , [ 1293771600000 , 114.84268599533] , [ 1296450000000 , 121.60793322282] , [ 1298869200000 , 133.41437346605] , [ 1301544000000 , 125.46646042904] , [ 1304136000000 , 129.76784954301] , [ 1306814400000 , 128.15798861044] , [ 1309406400000 , 121.92388706072] , [ 1312084800000 , 116.70036100870] , [ 1314763200000 , 88.367701837033] , [ 1317355200000 , 59.159665765725] , [ 1320033600000 , 79.793568139753] , [ 1322629200000 , 75.903834028417] , [ 1325307600000 , 72.704218209157] , [ 1327986000000 , 84.936990804097] , [ 1330491600000 , 93.388148670744]] 18 | }], 19 | "pie-chart": [ 20 | { "key": "One", "y": 5 }, 21 | { "key": "Two", "y": 2 }, 22 | { "key": "Three", "y": 9 }, 23 | { "key": "Four", "y": 7 }, 24 | { "key": "Five", "y": 4 }, 25 | { "key": "Six", "y": 3 }, 26 | { "key": "Seven", "y": 9 } 27 | ], 28 | "multi-bar-chart": [ 29 | { 30 | "key": "Series 1", 31 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , -6.3382185140371] , [ 1030766400000 , -5.9507873460847] , [ 1033358400000 , -11.569146943813] , [ 1036040400000 , -5.4767332317425] , [ 1038632400000 , 0.50794682203014] , [ 1041310800000 , -5.5310285460542] , [ 1043989200000 , -5.7838296963382] , [ 1046408400000 , -7.3249341615649] , [ 1049086800000 , -6.7078630712489] , [ 1051675200000 , 0.44227126150934] , [ 1054353600000 , 7.2481659343222] , [ 1056945600000 , 9.2512381306992] ] 32 | }, 33 | { 34 | "key": "Series 2", 35 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , 0] , [ 1030766400000 , 0] , [ 1033358400000 , 0] , [ 1036040400000 , 0] , [ 1038632400000 , 0] , [ 1041310800000 , 0] , [ 1043989200000 , 0] , [ 1046408400000 , 0] , [ 1049086800000 , 0] , [ 1051675200000 , 0] , [ 1054353600000 , 0] , [ 1056945600000 , 0] , [ 1059624000000 , 0] , [ 1062302400000 , 0] , [ 1064894400000 , 0] , [ 1067576400000 , 0] , [ 1070168400000 , 0] , [ 1072846800000 , 0] , [ 1075525200000 , -0.049184266875945] ] 36 | }, 37 | { 38 | "key": "Series 3", 39 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , -6.3382185140371] , [ 1030766400000 , -5.9507873460847] , [ 1033358400000 , -11.569146943813] , [ 1036040400000 , -5.4767332317425] , [ 1038632400000 , 0.50794682203014] , [ 1041310800000 , -5.5310285460542] , [ 1043989200000 , -5.7838296963382] , [ 1046408400000 , -7.3249341615649] , [ 1049086800000 , -6.7078630712489] , [ 1051675200000 , 0.44227126150934] , [ 1054353600000 , 7.2481659343222] , [ 1056945600000 , 9.2512381306992] ] 40 | }, 41 | { 42 | "key": "Series 4", 43 | "values": [ [ 1025409600000 , -7.0674410638835] , [ 1028088000000 , -14.663359292964] , [ 1030766400000 , -14.104393060540] , [ 1033358400000 , -23.114477037218] , [ 1036040400000 , -16.774256687841] , [ 1038632400000 , -11.902028464000] , [ 1041310800000 , -16.883038668422] , [ 1043989200000 , -19.104223676831] , [ 1046408400000 , -20.420523282736] , [ 1049086800000 , -19.660555051587] , [ 1051675200000 , -13.106911231646] , [ 1054353600000 , -8.2448460302143] , [ 1056945600000 , -7.0313058730976] ] 44 | } 45 | ], 46 | "cumulative-line-chart": [ 47 | { 48 | "key": "Series 1", 49 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , -6.3382185140371] , [ 1030766400000 , -5.9507873460847] , [ 1033358400000 , -11.569146943813] , [ 1036040400000 , -5.4767332317425] , [ 1038632400000 , 0.50794682203014] , [ 1041310800000 , -5.5310285460542] , [ 1043989200000 , -5.7838296963382] , [ 1046408400000 , -7.3249341615649] , [ 1049086800000 , -6.7078630712489] , [ 1051675200000 , 0.44227126150934] , [ 1054353600000 , 7.2481659343222] , [ 1056945600000 , 9.2512381306992] ] 50 | }, 51 | { 52 | "key": "Series 2", 53 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , 0] , [ 1030766400000 , 0] , [ 1033358400000 , 0] , [ 1036040400000 , 0] , [ 1038632400000 , 0] , [ 1041310800000 , 0] , [ 1043989200000 , 0] , [ 1046408400000 , 0] , [ 1049086800000 , 0] , [ 1051675200000 , 0] , [ 1054353600000 , 0] , [ 1056945600000 , 0] , [ 1059624000000 , 0] , [ 1062302400000 , 0] , [ 1064894400000 , 0] , [ 1067576400000 , 0] , [ 1070168400000 , 0] , [ 1072846800000 , 0] , [ 1075525200000 , -0.049184266875945] ] 54 | }, 55 | { 56 | "key": "Series 3", 57 | "values": [ [ 1025409600000 , 0] , [ 1028088000000 , -6.3382185140371] , [ 1030766400000 , -5.9507873460847] , [ 1033358400000 , -11.569146943813] , [ 1036040400000 , -5.4767332317425] , [ 1038632400000 , 0.50794682203014] , [ 1041310800000 , -5.5310285460542] , [ 1043989200000 , -5.7838296963382] , [ 1046408400000 , -7.3249341615649] , [ 1049086800000 , -6.7078630712489] , [ 1051675200000 , 0.44227126150934] , [ 1054353600000 , 7.2481659343222] , [ 1056945600000 , 9.2512381306992] ] 58 | }, 59 | { 60 | "key": "Series 4", 61 | "values": [ [ 1025409600000 , -7.0674410638835] , [ 1028088000000 , -14.663359292964] , [ 1030766400000 , -14.104393060540] , [ 1033358400000 , -23.114477037218] , [ 1036040400000 , -16.774256687841] , [ 1038632400000 , -11.902028464000] , [ 1041310800000 , -16.883038668422] , [ 1043989200000 , -19.104223676831] , [ 1046408400000 , -20.420523282736] , [ 1049086800000 , -19.660555051587] , [ 1051675200000 , -13.106911231646] , [ 1054353600000 , -8.2448460302143] , [ 1056945600000 , -7.0313058730976] ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /app/demos/tutorial1.csv: -------------------------------------------------------------------------------- 1 | For charts (type 2),United Kingdom,Switzerland,Sweden,Netherlands,Germany,France,Canada,Belgium,Australia,United States,Comparable Country Average,Japan,Austria 2 | 1970,4%,5%,7%,,6%,5%,7%,4%,,7%,5%,4%,5% 3 | 1971,5%,6%,7%,,6%,,7%,4%,5%,7%,6%,5%,5% 4 | 1972,5%,6%,7%,7%,7%,,7%,4%,5%,7%,6%,5%,5% 5 | 1973,5%,6%,7%,7%,7%,,7%,4%,5%,7%,6%,5%,5% 6 | 1974,5%,6%,7%,7%,8%,,6%,4%,6%,7%,6%,5%,5% 7 | 1975,5%,7%,7%,7%,8%,6%,7%,6%,6%,8%,7%,6%,7% 8 | 1976,5%,7%,8%,7%,8%,,7%,6%,6%,8%,7%,6%,7% 9 | 1977,5%,7%,8%,7%,8%,,7%,6%,7%,8%,7%,6%,7% 10 | 1978,5%,7%,9%,7%,8%,,7%,6%,6%,8%,7%,6%,7% 11 | 1979,5%,7%,8%,7%,8%,,7%,6%,6%,8%,7%,6%,7% 12 | 1980,6%,7%,9%,7%,8%,7%,7%,6%,6%,9%,7%,6%,7% 13 | 1981,6%,7%,9%,8%,9%,,7%,7%,6%,9%,7%,6%,7% 14 | 1982,6%,7%,9%,8%,9%,,8%,7%,6%,10%,8%,7%,6% 15 | 1983,6%,8%,9%,8%,9%,,8%,7%,6%,10%,8%,7%,6% 16 | 1984,6%,8%,9%,7%,9%,,8%,7%,6%,10%,7%,6%,6% 17 | 1985,6%,8%,8%,7%,9%,8%,8%,7%,6%,10%,8%,7%,6% 18 | 1986,6%,8%,8%,7%,9%,,8%,7%,7%,10%,8%,7%,7% 19 | 1987,6%,8%,8%,8%,9%,,8%,7%,6%,10%,8%,7%,7% 20 | 1988,6%,8%,8%,8%,9%,,8%,7%,6%,11%,8%,6%,7% 21 | 1989,6%,8%,8%,8%,8%,,8%,7%,6%,11%,8%,6%,7% 22 | 1990,6%,8%,8%,8%,8%,8%,9%,7%,7%,12%,8%,6%,8% 23 | 1991,6%,9%,8%,8%,,9%,9%,8%,7%,13%,8%,6%,8% 24 | 1992,7%,9%,8%,8%,10%,9%,10%,8%,7%,13%,9%,6%,9% 25 | 1993,7%,9%,8%,8%,10%,9%,10%,8%,7%,13%,9%,6%,9% 26 | 1994,7%,9%,8%,8%,10%,9%,9%,8%,7%,13%,9%,7%,10% 27 | 1995,7%,9%,8%,8%,10%,10%,9%,8%,7%,13%,9%,7%,10% 28 | 1996,7%,10%,8%,8%,10%,10%,9%,8%,7%,13%,9%,7%,10% 29 | 1997,6%,10%,8%,8%,10%,10%,9%,8%,7%,13%,9%,7%,10% 30 | 1998,7%,10%,8%,8%,10%,10%,9%,8%,8%,13%,9%,7%,10% 31 | 1999,7%,10%,8%,8%,10%,10%,9%,8%,8%,13%,9%,7%,10% 32 | 2000,7%,10%,8%,8%,10%,10%,9%,8%,8%,13%,9%,8%,10% 33 | 2001,7%,10%,9%,8%,11%,10%,9%,8%,8%,14%,9%,8%,10% 34 | 2002,8%,11%,9%,9%,11%,11%,9%,8%,8%,15%,9%,8%,10% 35 | 2003,8%,11%,9%,10%,11%,11%,10%,10%,8%,15%,10%,8%,10% 36 | 2004,8%,11%,9%,10%,11%,11%,10%,10%,9%,15%,10%,8%,10% 37 | 2005,8%,11%,9%,11%,11%,11%,10%,10%,8%,15%,10%,8%,10% 38 | 2006,8%,10%,9%,11%,11%,11%,10%,10%,8%,15%,10%,8%,10% 39 | 2007,8%,10%,9%,11%,10%,11%,10%,10%,9%,16%,10%,8%,10% 40 | 2008,9%,10%,9%,11%,11%,11%,10%,10%,9%,16%,10%,9%,10% 41 | 2009,10%,11%,10%,12%,12%,12%,11%,11%,9%,17%,11%,10%,11% 42 | 2010,9%,11%,9%,12%,12%,12%,11%,11%,9%,17%,11%,10%,11% 43 | 2011,9%,11%,9%,12%,11%,12%,11%,11%,9%,17%,11%,10%,11% 44 | 2012,9%,11%,10%,,11%,12%,11%,11%,,17%,11%,10%,11% 45 | -------------------------------------------------------------------------------- /app/demos/tutorial2.tsv: -------------------------------------------------------------------------------- 1 | Year Comparable Country Average United States 2 | 1995 4.526 12.26 3 | 1996 2.89 4 | 1997 6.876 13.46 5 | 1998 5.655 6 | 1999 8.058 15.41 7 | 2000 5.295714286 8 | 2001 5.905714286 20.11 9 | 2002 6.3 10 | 2003 6.191428571 21.97 11 | 2004 6.465 26.67 12 | 2005 6.905 13 | 2006 7.32375 26.58 14 | 2007 6.783333333 25.93 15 | 2008 7.795 16 | 2009 8.513333333 17 | 2010 9.74625 31.52 18 | 2011 10.15625 19 | 2012 10.84 34.45 20 | -------------------------------------------------------------------------------- /app/images/C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/C.png -------------------------------------------------------------------------------- /app/images/cumulativeLineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/cumulativeLineChart.png -------------------------------------------------------------------------------- /app/images/discreteBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/discreteBarChart.png -------------------------------------------------------------------------------- /app/images/donutChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/donutChart.png -------------------------------------------------------------------------------- /app/images/highcharts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/highcharts.png -------------------------------------------------------------------------------- /app/images/historicalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/historicalBarChart.png -------------------------------------------------------------------------------- /app/images/lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/lineChart.png -------------------------------------------------------------------------------- /app/images/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/map.png -------------------------------------------------------------------------------- /app/images/multiBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/multiBarChart.png -------------------------------------------------------------------------------- /app/images/multiBarHorizontalChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/multiBarHorizontalChart.png -------------------------------------------------------------------------------- /app/images/pieChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/pieChart.png -------------------------------------------------------------------------------- /app/images/scatterChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/scatterChart.png -------------------------------------------------------------------------------- /app/images/stackedAreaChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/stackedAreaChart.png -------------------------------------------------------------------------------- /app/images/tutorial1-requirement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/app/images/tutorial1-requirement.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | chartbuilder 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 33 |
34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/partials/about.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 |

Chartbuilder aims to simplify the process of turning your data into interactive visualization for the web. It has been built to leverage a wide range of existing chart libaries like d3 with nvd3 or highcharts, or to easily add more. Whether you want to build a simple chart from scratch, or to copy a data set from excel and tweak all the nitty-gritty options, Chartbuilder can fill the gap where you would otherwise need a programmer or designer to get visualizations ready for the web.

7 |

Chartbuilder is alpha software. Check back as we continue to add features and improve the experience.

8 |
9 |
10 | -------------------------------------------------------------------------------- /app/partials/chartbuilder.html: -------------------------------------------------------------------------------- 1 | 95 | -------------------------------------------------------------------------------- /app/partials/faq.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | 11 | 16 | 29 | 34 |
35 |
36 | -------------------------------------------------------------------------------- /app/partials/home.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 |
7 |
8 |

angular + d3 chartbuilder

9 | 19 |
20 |
21 | 22 |
23 |
24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /app/partials/tutorials.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 |

Scatter Plot With Trend Lines

7 |
8 |

Creating a scatter plot is pretty straightforward, but adding trend lines can be a little tricky. Lets tackle that with Chartbuilder.

9 |

We'll start by importing our data. Select Scatter Plus Line Chart as your chart type, then upload a tsv file containing data for the density of MRI units in the US vs other countries from 1995-2010 by clicking Add Existing Data -> Upload. The tsv file has some basic time series data that Chartbuilder will convert into groups for editing.

10 |
11 |

Scatter charts allow you to change the size and shape for the data point markers from the live edit table view. After that we can make a few more tweaks if we like. I've added text and scaled the y-axis to show 0-40.

12 |
13 |

Now comes the tricky part. The charting library doesn't do the calculations for the trend line automatically, so we'll have to do it ourselves, and input in the two special data group fields: slope and intercept. Slope can be calculated by via a simple equation:

y1 - y2 / x1 - x2 (You can use different points if you want to adjust the trend line.)
Intercept is the point on the Y-axis where the line intersects at x = 0. So for this data it's actually a little odd since we're using the numerical point values of the year. Finding the intercept:
[slope] x [-xmin] or 1.3052941176470592 x -1995
for the second line in our data. This calculation is imperfect, so we can nudge the intercept manually until we get the line in the right place. I settled on -2593. Be aware that if you change the Datatype of your axis, the calculation may change eg choosing Date for the X-axis would necessitate using the timestamp value in that calculation instead.

14 |

{{ tutorial2.meta.title }}

15 |

{{ tutorial2.meta.subtitle }}

16 | 17 |

{{ tutorial2.meta.caption }}

18 |
{{ tutorial2.meta.attribution }}
19 |
20 |
21 |

Line Chart with Two Highlight Lines

22 |
23 |

This one is a little different, since we only want to highlight two lines, but still show the rest. This is the chart we want to match:

24 |
25 | 26 |
27 |
28 |

There are some things we can't do with Chartbuilder, yet, like adding the persistent labels to a line, or adding a generic label. The chart we build is going to be a little different, and will supplement the plot lines with an interactive tooltip.

29 |
30 |

First, let's import data. In the csv file for this example we have years and percentages for several countries. The first column is a standard four digit year, the second is a formatted percentage. Upload the csv data to Chartbuilder by clicking Add Existing Data -> Upload. Now we have values populated in our data groups, and some plotted lines. To get these to plot properly for our line graph, we'll need to set the datatypes and formatters for our axis. For the first column, we set x-Axis Datatype to Date. This attempts to parse dates from the values in the first column, and handles most common date formats, like this four digit year as well as 2005-12-14, etc. Now the graph knows we are making a time series, and will plot accordingly. We can also use the available time formatters to make our axis label look like it should. xAxis -> Tick Formatter has a few available options. We'll pick Year (YYYY). As for the y-Axis, since our percent values are already formatted, we can use the default y-Axis Datatype of Y, and set the y-Axis Tick Formatter to Percent (unmultiplied). Other percent formatters take raw decimal data and multiply it to get percentages, but we don't need to do that here.

31 |
32 |

Next we want to adjust our scale, so that the y-Axis goes from 0 to 18%. Use the y-Axis Endpoints option to set 0 (the start) and 1 (the end) to 0 and 18.

33 |
34 |

To smooth the lines, set Interpolate to bundle.

35 |
36 |

Since we're using custom colors in this chart, click Enable Live Edit, and go through each data series to associate highlight colors with United States and Comparable Country Average, and a grey for the other comparison countries. Enable useInteractiveGuideline for a nice tooltip that tracks the mouse on the x-Axis and summarizes the value group.

37 |
38 |

It's not exact, but we have replicated the data plot for this graph, and have a nice interactive tooltip for line values instead of the static line labels. This graph is also responsive and can be styled to match your site's theme.

39 |
40 |

{{ tutorial1.meta.title }}

41 |

{{ tutorial1.meta.subtitle }}

42 | 43 |

{{ tutorial1.meta.caption }}

44 |
{{ tutorial1.meta.attribution }}
45 |
46 |
47 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/chartbuilder-options/options-constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var d3 = require('d3'); 4 | 5 | // Normalize dates 6 | function normalizedDate(date) { 7 | var d = new Date(Date.parse(date)); 8 | return new Date(d.getTime() + d.getTimezoneOffset() * 60000); 9 | } 10 | 11 | var xKeyValue = { 12 | 'label': 'Key', 13 | 'option': function(d) { 14 | return d.key; 15 | } 16 | } 17 | 18 | var xLabelValue = { 19 | 'label': 'Label', 20 | 'option': function(d) { 21 | return d.label; 22 | } 23 | } 24 | 25 | var xValue = { 26 | 'label': 'X', 27 | 'option': function(d) { 28 | return d.x; 29 | } 30 | } 31 | 32 | var yValue = { 33 | 'label': 'Y', 34 | 'option': function(d) { 35 | return d.y; 36 | } 37 | } 38 | 39 | var yPercent = { 40 | 'label': 'Y Percent Value', 41 | 'option': function(d) { 42 | return d.y / 100; 43 | } 44 | } 45 | 46 | var yLabelValue = { 47 | 'label': 'Value', 48 | 'option': function(d) { 49 | return d.value; 50 | } 51 | } 52 | 53 | var formatters = { 54 | 'function:text': { 55 | 'label': 'Text (unformatted)', 56 | 'option': function(d) { 57 | return d; 58 | } 59 | }, 60 | 'function:percent': { 61 | 'label': 'Percent (no decimal)', 62 | 'option': function(d) { 63 | return d3.format('.0%')(d); 64 | } 65 | }, 66 | 'function:percent-.1': { 67 | 'label': 'Percent (0.1%)', 68 | 'option': function(d) { 69 | return d3.format('.1%')(d); 70 | } 71 | }, 72 | 'function:percent-.01': { 73 | 'label': 'Percent (0.01%)', 74 | 'option': function(d) { 75 | return d3.format('.2%')(d); 76 | } 77 | }, 78 | 'function:percent-unmultiplied': { 79 | 'label': 'Percent (unmultiplied)', 80 | 'option': function(d) { 81 | return d3.format('.0%')(d / 100); 82 | } 83 | }, 84 | 'function:price': { 85 | 'label': 'Currency (no decimal)', 86 | 'option': function(d) { 87 | return d3.format('$,.0f')(d); 88 | } 89 | }, 90 | 'function:price-.1': { 91 | 'label': 'Currency ($0.1)', 92 | 'option': function(d) { 93 | return d3.format('$,.1f')(d); 94 | } 95 | }, 96 | 'function:price-.01': { 97 | 'label': 'Currency ($.01)', 98 | 'option': function(d) { 99 | return d3.format('$,.2f')(d); 100 | } 101 | }, 102 | 'function:year': { 103 | 'label': 'Year (\'YY)', 104 | 'option': function(d) { 105 | return d3.time.format('\'%y')(new Date(d)); 106 | } 107 | }, 108 | 'function:year-yyyy': { 109 | 'label': 'Year (YYYY)', 110 | 'option': function(d) { 111 | return d3.time.format('%Y')(new Date(d)); 112 | } 113 | } 114 | } 115 | 116 | angular 117 | 118 | .module('chartbuilderOptions') 119 | 120 | .value('chartbuilderOptionHelp', { 121 | 'forceX': { 122 | 'help': 'Set the min (0) and the max (1) values to scale this axis to', 123 | 'label': 'x-Axis Endpoints' 124 | }, 125 | 'forceY': { 126 | 'help': 'Set the min (0) and the max (1) values to scale this axis to', 127 | 'label': 'y-Axis Endpoints' 128 | }, 129 | 'x': { 130 | 'help': 'Select the correct data type for values on this axis', 131 | 'label': 'x-Axis Datatype' 132 | }, 133 | 'y': { 134 | 'help': 'Select the correct data type for values on this axis', 135 | 'label': 'y-Axis Datatype' 136 | }, 137 | 'showXAxis': { 138 | 'label': 'Show x-Axis' 139 | }, 140 | 'showYAxis': { 141 | 'label': 'Show y-Axis' 142 | }, 143 | 'staggerLabels': { 144 | 'label': 'Stagger Tick Labels' 145 | }, 146 | 'rightAlignYAxis': { 147 | 'label': 'Align y-Axis to the right' 148 | }, 149 | 'tooltips': { 150 | 'label': 'Show Tooltips' 151 | }, 152 | 'tickFormat': { 153 | 'label': 'Tick Formatter' 154 | }, 155 | 'valueFormat': { 156 | 'label': 'Value Formatter' 157 | }, 158 | 'margin': { 159 | 'help': 'Adjust the whitespace around this element', 160 | 'label': 'Margin' 161 | } 162 | }) 163 | 164 | .value('chartbuilderOptionValues', { 165 | 166 | // 167 | // NVD3 options 168 | // 169 | 170 | 'interpolate': { 171 | 'linear': { 172 | 'label': 'linear' 173 | }, 174 | 'linear-closed': { 175 | 'label': 'linear-closed' 176 | }, 177 | 'step-before': { 178 | 'label': 'step-before' 179 | }, 180 | 'step-after': { 181 | 'label': 'step-after' 182 | }, 183 | 'basis': { 184 | 'label': 'basis' 185 | }, 186 | 'basis-open': { 187 | 'label': 'basis-open' 188 | }, 189 | 'basis-closed': { 190 | 'label': 'basis-closed' 191 | }, 192 | 'bundle': { 193 | 'label': 'bundle' 194 | }, 195 | 'cardinal': { 196 | 'label': 'bundle' 197 | }, 198 | 'cardinal-open': { 199 | 'label': 'cardinal-open' 200 | }, 201 | 'cardinal-closed': { 202 | 'label': 'cardinal-closed' 203 | }, 204 | 'monotone': { 205 | 'label': 'monotone' 206 | } 207 | }, 208 | 'style': { 209 | 'stack': { 210 | 'label': 'stack' 211 | }, 212 | 'stream': { 213 | 'label': 'stream' 214 | }, 215 | 'stream-center': { 216 | 'label': 'stream-center' 217 | }, 218 | 'expand': { 219 | 'label': 'expand' 220 | }, 221 | 'stack_percent': { 222 | 'label': 'stack_percent' 223 | } 224 | }, 225 | 'labelType': { 226 | 'key': { 227 | 'label': 'key' 228 | }, 229 | 'value': { 230 | 'label': 'value' 231 | }, 232 | 'percent': { 233 | 'label': 'percent' 234 | } 235 | }, 236 | 'valueFormat': formatters, 237 | 'tickFormat': formatters, 238 | 'x': { 239 | 'function:key/value': xKeyValue, 240 | 'function:x/y': xValue, 241 | 'function:label/value': xLabelValue, 242 | 'function:timestamp': { 243 | 'label': 'Timestamp', 244 | 'option': function(d) { 245 | if (isNaN(d.x)) { 246 | return null; 247 | } 248 | return new Date(+d.x); 249 | } 250 | }, 251 | 'function:date': { 252 | 'label': 'Date', 253 | 'option': function(d) { 254 | return normalizedDate(d.x); 255 | } 256 | }, 257 | 'function:datefromarray': { 258 | 'label': 'Date (Stacked Area)', 259 | 'option': function(d) { 260 | return normalizedDate(d[0]); 261 | } 262 | } 263 | }, 264 | 'y': { 265 | 'function:key/y': yValue, 266 | 'function:yPercentData': yPercent, 267 | 'function:label/value': yLabelValue, 268 | 'function:valuefromarray': { 269 | 'label': 'Value (Stacked Area)', 270 | 'option': function(d) { 271 | return d[1]; 272 | } 273 | } 274 | }, 275 | 'tooltipContent': { 276 | 'function:key/value': { 277 | 'label': 'key/value', 278 | 'option': function(key, y, e, graph) { 279 | return '

' + key + '

' +'

' + y + '

' ; 280 | } 281 | }, 282 | 'function:value only': { 283 | 'label': 'value only', 284 | 'option': function(key, y) { 285 | return '

' + y + '

'; 286 | } 287 | }, 288 | 'function:key only': { 289 | 'label': 'key only', 290 | 'option': function(key) { 291 | return '

' + key + '

'; 292 | } 293 | }, 294 | 'Default': { 295 | 'label': 'Default', 296 | 'option': null 297 | } 298 | }, 299 | 'tooltip': { 300 | 'function:multiBarChart': { 301 | 'label': 'multiBarChart', 302 | 'option': function(key, x, y) { 303 | return '

' + key + '

' + 304 | '

' + y + ' ' + x + '

'; 305 | } 306 | }, 307 | 'Default': { 308 | 'label': 'Default', 309 | 'option': null 310 | } 311 | }, 312 | 'fillQuartiles': { 313 | 'function:flat': { 314 | 'label': 'flat', 315 | 'option': function(d) { 316 | return d/4; 317 | } 318 | } 319 | }, 320 | 321 | // 322 | // Datamaps options 323 | // 324 | 'mapType': { 325 | 'usa': { 326 | 'label': 'usa' 327 | }, 328 | 'world': { 329 | 'label': 'world' 330 | } 331 | } 332 | }); 333 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/chartbuilder-options/options.html: -------------------------------------------------------------------------------- 1 | 80 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/chartbuilder-options/options.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('../../directives/module'); 4 | 5 | angular 6 | 7 | .module('chartbuilderOptions', ['chartbuilderDirectives']) 8 | 9 | .service('chartbuilderDefaultOptions', function() { 10 | var defaultOptions = { 11 | 12 | options: false, 13 | 14 | load: function(options) { 15 | this.options = options; 16 | } 17 | 18 | } 19 | 20 | return defaultOptions; 21 | }) 22 | 23 | .service('chartbuilderOptionValueKeys', ['chartbuilderOptionValues', function(chartbuilderOptionValues) { 24 | return (chartbuilderOptionValues instanceof Object) ? Object.keys(chartbuilderOptionValues) : []; 25 | }]) 26 | 27 | .directive('chartbuilderOptions', ['$compile', 'chartbuilderUtils', 'chartbuilderOptionValues', 'chartbuilderOptionValueKeys', 'chartbuilderOptionHelp', function($compile, chartbuilderUtils, chartbuilderOptionValues, chartbuilderOptionValueKeys, chartbuilderOptionHelp) { 28 | return { 29 | restrict: 'EA', 30 | scope: { 31 | key: '@?', 32 | json: '=', 33 | node: '=?', 34 | children: '=?', 35 | collapsedLevel: '@' 36 | }, 37 | controller: function($scope) { 38 | 39 | // Initialize container for child nodes 40 | $scope.children = {}; 41 | 42 | // Initialize container for function options 43 | $scope.functionOptions = {}; 44 | $scope.selectedOptions = {}; 45 | 46 | // Define auxiliary functions 47 | $scope.utils = { 48 | 49 | // collapse/expand node by clicking 50 | clickNode: function(node) { 51 | node.isCollapsed = !node.isCollapsed; 52 | }, 53 | 54 | listSelector: { 55 | init: function(key) { 56 | if (key in chartbuilderOptionValues) { 57 | $scope.selectedOptions[key] = $scope.json[key] || chartbuilderUtils.keys(chartbuilderOptionValues[key])[0]; 58 | $scope.functionOptions[key] = chartbuilderOptionValues[key]; 59 | } 60 | }, 61 | onChange: function(item, key) { 62 | $scope.json[key] = 'Default' === item ? null : item; 63 | } 64 | }, 65 | 66 | // Skip ordering in ng-repeat 67 | keys: function(json) { 68 | return chartbuilderUtils.keys(json); 69 | }, 70 | 71 | // Hide some options 72 | isHidden: function(key) { 73 | return [ 74 | 'type', 75 | 'dispatch', 76 | 'noData', 77 | 'id' 78 | ].indexOf(key) > -1; 79 | } 80 | }; 81 | 82 | // Define properties of the current node 83 | $scope.node = { 84 | 85 | // Check node is collapsed 86 | isCollapsed: ($scope.collapsedLevel && +$scope.collapsedLevel) ? (+$scope.collapsedLevel <= 0) : true, /* set up isCollapsed properties, by default - true */ 87 | 88 | // Check current node is object or array 89 | isObject: function() { 90 | return angular.isObject($scope.json) 91 | }, 92 | 93 | // Get type for current node 94 | type: function() { 95 | var type = chartbuilderUtils.getType($scope.json); 96 | 97 | if (type === 'function' 98 | || (type === 'string' 99 | && ( 100 | chartbuilderOptionValueKeys.indexOf($scope.key) > -1 101 | ) 102 | ) 103 | || $scope.selectedOptions[$scope.key] 104 | ) { 105 | return 'selector'; 106 | } 107 | 108 | return type; 109 | }, 110 | 111 | // Calculate collection length for object or array 112 | length: function() { 113 | return ($scope.json instanceof Object) ? (Object.keys($scope.json).length) : 1 114 | }, 115 | 116 | help: function() { 117 | if (chartbuilderOptionHelp.hasOwnProperty($scope.key)) { 118 | return chartbuilderOptionHelp[$scope.key]; 119 | } 120 | }, 121 | 122 | // Refresh template view 123 | refresh: function() { 124 | $scope.refresh(); 125 | } 126 | }; 127 | }, 128 | link: function(scope, element, attrs) { 129 | // Define child scope and template 130 | var childScope = scope.$new(), 131 | template = require('./options.html'); 132 | 133 | // Define build template function 134 | scope.build = function(_scope) { 135 | if (scope.node.isObject()) { 136 | element.html('').append($compile(template)(_scope)); 137 | } 138 | }; 139 | 140 | // Define refresh function 141 | scope.refresh = function() { 142 | childScope.$destroy(); 143 | childScope = scope.$new(); 144 | scope.build(childScope); 145 | }; 146 | 147 | // Build template view 148 | scope.build(childScope); 149 | } 150 | } 151 | }]); 152 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/datamaps/angular-datamaps.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | 5 | .module('datamaps', []) 6 | 7 | .directive('datamap', ['$compile', 'getGeoCodeMap', function($compile, getGeoCodeMap) { 8 | return { 9 | restrict: 'EA', 10 | scope: { 11 | data: '=', //map data, [required] 12 | options: '=', //map options, [required] 13 | colors: '=?', //map colors array, [optional] 14 | events: '=?', //global events that directive would subscribe to, [optional] 15 | type: '@?', //map scope, world or usa, [optional, defaults to usa] 16 | }, 17 | template: '
', 18 | link: function(scope, element, attrs) { 19 | scope.mapOptions = mapOptions(); 20 | 21 | scope.api = { 22 | 23 | // Fully refresh directive 24 | refresh: function() { 25 | scope.api.updateWithOptions(scope.options, scope.data[0]); 26 | }, 27 | 28 | selectDataSet: function(selection) { 29 | var selectedData = scope.data[selection]; 30 | scope.api.updateWithOptions(scope.options, selectedData); 31 | }, 32 | 33 | datasetSelector: function() { 34 | var selector = $compile('')(scope); 35 | element.append(selector); 36 | }, 37 | 38 | // Update chart with new options 39 | updateWithOptions: function(options, data) { 40 | var _options; 41 | 42 | // Clearing 43 | scope.api.clearElement(); 44 | 45 | // Exit if options are not yet bound 46 | if (!angular.isDefined(options)) return; 47 | 48 | // Update bounding box 49 | scope.width = options.chart.width || 600; 50 | scope.height = options.chart.height || scope.width * 0.6; 51 | 52 | scope.mapOptions = mapOptions(); 53 | scope.geoCodeMap = getGeoCodeMap.get(scope.mapOptions.scope); 54 | 55 | // Add data to map redraw 56 | if (data.values.length) { 57 | // update the map element 58 | scope.mapOptions = mapData(scope.mapOptions, data.values); 59 | } 60 | 61 | scope.mapOptions.geographyConfig = angular.extend({}, options.chart.geographyConfig); 62 | 63 | scope.map = new Datamap(scope.mapOptions); 64 | 65 | if (!options.chart) return; 66 | 67 | // set labels 68 | if (options.chart.labels) { 69 | scope.map.labels({ 70 | labelColor: options.chart.labelColor ? options.chart.labelColor : '#333333', 71 | fontSize: options.chart.labelSize ? options.chart.labelSize : 12 72 | }); 73 | } 74 | 75 | // set legend 76 | if (options.chart.legend) { 77 | scope.map.legend(); 78 | } 79 | 80 | }, 81 | 82 | // Update chart with new data 83 | updateWithData: function(data) { 84 | scope.map.updateChoropleth(data); 85 | }, 86 | 87 | // Fully clear directive element 88 | clearElement: function () { 89 | scope.map = null; 90 | element.find('#map-container').empty(); 91 | } 92 | }; 93 | 94 | // Watching on options, colors changing 95 | scope.$watch('[options, colors]', function() { 96 | scope.api.refresh(); 97 | }, true); 98 | 99 | // Watch data changing. Only refresh if options or data map points have changed 100 | scope.$watch('data', function(data, old) { 101 | if (!data.length) { 102 | scope.api.updateWithData({ values: [] }); 103 | } 104 | else if (old.length && (data[0].values || []).length !== (old[0].values || []).length) { 105 | scope.api.refresh(); 106 | } 107 | else { 108 | var _data = {}; 109 | angular.forEach(data[0].values, function(val) { 110 | _data[scope.geoCodeMap[val.location] || val.location] = { fillKey: val.value }; 111 | }); 112 | scope.api.updateWithData(_data); 113 | } 114 | if (data.length > 1) { 115 | scope.api.datasetSelector(); 116 | } 117 | }, true); 118 | 119 | //subscribe on global events 120 | angular.forEach(scope.events, function(eventHandler, event) { 121 | scope.$on(event, function(e){ 122 | return eventHandler(e, scope); 123 | }); 124 | }); 125 | 126 | // Generate base map options 127 | function mapOptions() { 128 | return { 129 | element: element[0].children[0], 130 | scope: (scope.type === 'usa' || scope.type === 'world') ? scope.type : 'usa', 131 | height: scope.height, 132 | width: scope.width, 133 | projection: scope.type === 'world' ? 'mercator' : 'equirectangular', 134 | fills: { 135 | defaultFill: '#b9b9b9' 136 | }, 137 | data: {} 138 | } 139 | }; 140 | 141 | // Extend the mapOptions object with data and fill values 142 | function mapData(dst, data) { 143 | angular.forEach(data, function(val) { 144 | dst.data[scope.geoCodeMap[val.location] || val.location] = { fillKey: val.value }; 145 | }); 146 | 147 | if (!scope.options.fillQuartiles) { 148 | var fillKeys = []; 149 | angular.forEach(data, function(data) { 150 | if (fillKeys.indexOf(data.value) === -1) { 151 | fillKeys.push(data.value); 152 | } 153 | }); 154 | 155 | angular.forEach(fillKeys, function(key, idx) { 156 | dst.fills[key] = scope.colors[idx]; 157 | }); 158 | } 159 | else { 160 | // @TODO Map numeric ranges to quartiles 161 | } 162 | 163 | return dst; 164 | } 165 | } 166 | }; 167 | }]) 168 | 169 | .service('getGeoCodeMap', function() { 170 | // Map the geography codes so we can assign them properly 171 | this.datamaps = Datamap.prototype; 172 | this.get = function(geoContext) { 173 | var _this = this, 174 | geos = {}; 175 | angular.forEach(_this.datamaps[geoContext + 'Topo'].objects[geoContext].geometries, function(geo) { 176 | geos[geo.properties.name] = geo.id; 177 | }); 178 | return geos; 179 | }; 180 | }); 181 | 182 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/datamaps/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [{ 3 | "key": "Numbers", 4 | "values": [ 5 | { "location": "NY", "value": 'Y' }, 6 | { "location": "CA", "value": 'Y' }, 7 | { "location": "TX", "value": 'N' }, 8 | { "location": "DE", "value": 'Y' }, 9 | { "location": "VA", "value": 'N' }, 10 | { "location": "FL", "value": 'N' }, 11 | { "location": "GA", "value": 'Y' }, 12 | { "location": "HI", "value": 'Y' } 13 | ] 14 | }] 15 | }); 16 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/datamaps/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('../../services/services'); 4 | require('topojson'); 5 | require('datamaps'); 6 | require('./angular-datamaps'); 7 | 8 | /** 9 | * Chartbuilder Data Maps module 10 | */ 11 | 12 | var module = { 13 | name: 'Maps', 14 | slug: 'map', 15 | data: require('./data') 16 | }; 17 | 18 | var template = [''].join(''); 24 | 25 | angular 26 | 27 | .module('chartbuilder.datamaps', ['chartbuilderServices', 'datamaps']) 28 | 29 | .value('chartbuilderModuleRegistry', {}) 30 | 31 | .value('chartbuilderSelectedModule', '') 32 | 33 | /** 34 | * Add this module's state to ui-router routes 35 | */ 36 | .config(['$stateProvider', function($stateProvider) { 37 | $stateProvider.state('chartbuilder.' + module.slug, { 38 | url: '/' + module.slug, 39 | views: { 40 | 'graph': { 41 | template: template, 42 | controller: module.slug + 'Controller' 43 | } 44 | } 45 | }); 46 | }]) 47 | 48 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 49 | var moduleOpts = {}; 50 | moduleOpts[module.name] = { 51 | name: module.name, 52 | slug: module.slug, 53 | data: module.data, 54 | dataFormat: [{ 'key': 'location', 'type': 'text' }, { 'key': 'value', 'type': 'text' }], 55 | dataHelp: 'Data may be entered with the first column as the geography, and subsequent columns as the values. When uploading or pasting data, subsequent columns will be treated as a new data group. The columns values in the first row will be assigned as the group name; the first value can be either "location" or a blank.', 56 | template: template, 57 | meta: { 58 | title: module.name, 59 | subtitle: 'Subtitle for a map', 60 | caption: '1a. Edit a caption for a map', 61 | }, 62 | options: { 63 | chart: { 64 | mapType: 'usa', 65 | height: null, 66 | width: 800, 67 | legend: true, 68 | labels: true, 69 | labelColor: '#333333', 70 | labelSize: 12, 71 | fillQuartiles: function(d) { 72 | return d/4; 73 | }, 74 | geographyConfig: { 75 | hideAntarctica: true, 76 | borderWidth: 1, 77 | borderColor: '#FDFDFD', 78 | popupOnHover: true, 79 | highlightOnHover: true, 80 | highlightFillColor: '#FC8D59', 81 | highlightBorderColor: 'rgba(250, 15, 160, 0.2)', 82 | highlightBorderWidth: 2 83 | }, 84 | } 85 | } 86 | } 87 | 88 | // Add the slug and name definitions to chartbuilder 89 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 90 | } 91 | ]) 92 | 93 | .controller(module.slug + 'Controller', [ 94 | '$scope', 95 | 'chartbuilderData', 96 | 'chartbuilderModuleRegistry', 97 | 'chartbuilderSelectedModule', 98 | function($scope, chartbuilderData, chartbuilderModuleRegistry, chartbuilderSelectedModule) { 99 | // Localize the datastore for the view 100 | $scope.dataStore = chartbuilderData; 101 | 102 | // Initialize the data -- store sample data and set structure 103 | chartbuilderSelectedModule = module.slug; 104 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 105 | } 106 | ]); 107 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/highcharts/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [{ 3 | type: 'column', 4 | name: 'Jane', 5 | data: [3, 2, 1, 3, 4] 6 | }, 7 | { 8 | type: 'column', 9 | name: 'John', 10 | data: [2, 3, 5, 7, 6] 11 | }, 12 | { 13 | type: 'column', 14 | name: 'Joe', 15 | data: [4, 3, 3, 9, 0] 16 | }, 17 | { 18 | type: 'spline', 19 | name: 'Average', 20 | data: [3, 2.67, 3, 6.33, 3.33], 21 | marker: { 22 | lineWidth: 2, 23 | lineColor: Highcharts.getOptions().colors[3], 24 | fillColor: 'white' 25 | } 26 | }, 27 | { 28 | type: 'pie', 29 | name: 'Total consumption', 30 | data: [{ 31 | name: 'Jane', 32 | y: 13, 33 | color: Highcharts.getOptions().colors[0] // Jane's color 34 | }, { 35 | name: 'John', 36 | y: 23, 37 | color: Highcharts.getOptions().colors[1] // John's color 38 | }, { 39 | name: 'Joe', 40 | y: 19, 41 | color: Highcharts.getOptions().colors[2] // Joe's color 42 | }], 43 | center: [100, 80], 44 | size: 100, 45 | showInLegend: false, 46 | dataLabels: { 47 | enabled: false 48 | } 49 | }] 50 | }); 51 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/highcharts/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Highcharts = require('../../../bower_components/highcharts/highcharts-all'); 4 | require('../../../bower_components/highcharts-ng/dist/highcharts-ng'); 5 | 6 | /* 7 | Chartbuilder Highcharts module 8 | */ 9 | 10 | var module = { 11 | name: 'Highcharts', 12 | slug: 'highcharts', 13 | data: require('./data') 14 | }; 15 | 16 | var template = [''].join(''); 18 | 19 | angular 20 | 21 | .module('chartbuilder.highcharts', ['highcharts-ng', 'chartbuilderServices']) 22 | 23 | .value('chartbuilderModuleRegistry', {}) 24 | 25 | .value('chartbuilderSelectedModule', '') 26 | 27 | /** 28 | * Add this module's state to ui-router routes 29 | */ 30 | .config(['$stateProvider', function($stateProvider) { 31 | $stateProvider.state('chartbuilder.' + module.slug, { 32 | url: '/' + module.slug, 33 | views: { 34 | 'graph': { 35 | template: template, 36 | controller: module.slug + 'Controller' 37 | } 38 | } 39 | }); 40 | }]) 41 | 42 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 43 | var moduleOpts = {}; 44 | moduleOpts[module.name] = { 45 | name: module.name, 46 | slug: module.slug, 47 | data: module.data, 48 | dataFormat: [{ 'key': 'location', 'type': 'text' }, { 'key': 'value', 'type': 'text' }], 49 | template: template, 50 | meta: { 51 | title: module.name, 52 | subtitle: 'Subtitle for a map', 53 | caption: '1a. Edit a caption for a map', 54 | }, 55 | highcharts: { 56 | xAxis: { 57 | categories: ['Apples', 'Oranges', 'Pears', 'Bananas', 'Plums'] 58 | }, 59 | labels: { 60 | items: [{ 61 | html: 'Total fruit consumption', 62 | style: { 63 | left: '50px', 64 | top: '18px', 65 | color: (Highcharts.theme && Highcharts.theme.textColor) || 'black' 66 | } 67 | }] 68 | }, 69 | series: [], 70 | size: { 71 | height: 600 72 | }, 73 | title: { 74 | text: '' 75 | } 76 | } 77 | } 78 | 79 | // Add the slug and name definitions to chartbuilder 80 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 81 | } 82 | ]) 83 | 84 | .controller(module.slug + 'Controller', [ 85 | '$scope', 86 | 'chartbuilderData', 87 | 'chartbuilderModuleRegistry', 88 | 'chartbuilderSelectedModule', 89 | function($scope, chartbuilderData, chartbuilderModuleRegistry, chartbuilderSelectedModule) { 90 | // Localize the datastore for the view 91 | $scope.dataStore = chartbuilderData; 92 | 93 | // Initialize the data -- store sample data and set structure 94 | chartbuilderSelectedModule = module.slug; 95 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 96 | 97 | $scope.$watch('chartbuilderData.data', function() { 98 | chartbuilderData.syncData(); 99 | }, true); 100 | } 101 | ]); 102 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/chartbuilderNvd3.js: -------------------------------------------------------------------------------- 1 | require('nvd3'); 2 | require('./angular-nvd3'); 3 | require('./lineChart/main'); 4 | require('./lineWithFocusChart/main'); 5 | require('./cumulativeLineChart/main'); 6 | require('./discreteBarChart/main'); 7 | require('./multiBarChart/main'); 8 | require('./multiBarHorizontalChart/main'); 9 | require('./pieChart/main'); 10 | require('./historicalBarChart/main'); 11 | require('./stackedAreaChart/main'); 12 | require('./scatterChart/main'); 13 | require('./scatterPlusLineChart/main'); 14 | 15 | angular 16 | 17 | .module('chartbuilder.nvd3', [ 18 | 'angular-nvd3', 19 | 'chartbuilder.nvd3.lineChart', 20 | 'chartbuilder.nvd3.lineWithFocusChart', 21 | 'chartbuilder.nvd3.cumulativeLineChart', 22 | 'chartbuilder.nvd3.discreteBarChart', 23 | 'chartbuilder.nvd3.multiBarChart', 24 | 'chartbuilder.nvd3.multiBarHorizontalChart', 25 | 'chartbuilder.nvd3.pieChart', 26 | 'chartbuilder.nvd3.historicalBarChart', 27 | 'chartbuilder.nvd3.stackedAreaChart', 28 | 'chartbuilder.nvd3.scatterChart', 29 | 'chartbuilder.nvd3.scatterPlusLineChart' 30 | ]); 31 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/cumulativeLineChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the cumulativeLineChart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Cumulative Line Chart', 8 | slug: 'cumulativeLineChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.cumulativeLineChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'x', 'type': 'number' }, { 'key': 'y', 'type': 'number' }], 44 | template: template, 45 | meta: { 46 | title: module.name, 47 | subtitle: 'Subtitle for a line chart', 48 | caption: '1a. Edit a caption for the graph', 49 | }, 50 | options: { 51 | chart: { 52 | type: module.slug, 53 | height: 600, 54 | useVoronoi: false, 55 | x: 'function:timestamp', 56 | y: 'function:yPercentData', 57 | xAxis: { 58 | tickFormat: 'function:year' 59 | }, 60 | yAxis: { 61 | tickFormat: 'function:percent' 62 | }, 63 | forceX: [null, null], 64 | forceY: [null, null] 65 | } 66 | } 67 | } 68 | 69 | // Add the slug and name definitions to chartbuilder 70 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 71 | } 72 | ]) 73 | 74 | .controller(module.slug + 'Controller', [ 75 | '$scope', 76 | 'chartbuilderData', 77 | 'chartbuilderModuleRegistry', 78 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 79 | // Localize the datastore for the view 80 | $scope.dataStore = chartbuilderData; 81 | 82 | // Initialize the data -- store sample data and set structure 83 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 84 | } 85 | ]); 86 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/discreteBarChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [{ 3 | "key": "Cumulative Return", 4 | "values": [ 5 | { "label": "A", "value": -29.765957771107 }, 6 | { "label": "B", "value": 0 }, 7 | { "label": "C", "value": 32.807804682612 }, 8 | { "label": "D", "value": 196.45946739256 }, 9 | { "label": "E", "value": 0.19434030906893 }, 10 | { "label": "F", "value": -98.079782601442 }, 11 | { "label": "G", "value": -13.925743130903 }, 12 | { "label": "H", "value": -5.1387322875705 } 13 | ] 14 | }] 15 | }); 16 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/discreteBarChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the bar chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Bar Chart', 8 | slug: 'discreteBarChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.discreteBarChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'label', 'type': 'text' }, { 'key': 'value', 'type': 'number' }], 44 | dataHelp: 'The first column will be the label for the bar, and subsequent columns will be added as data groups. Subsequent columns must be in a numerical format so values can be plotted against the y-axis.', 45 | template: template, 46 | meta: { 47 | title: module.name, 48 | subtitle: 'Subtitle for a bar chart', 49 | caption: '1a. Edit a caption for the graph', 50 | }, 51 | options: { 52 | chart: { 53 | type: module.slug, 54 | height: 600, 55 | x: 'function:label/value', 56 | y: 'function:label/value', 57 | showValues: true, 58 | forceX: [null, null], 59 | forceY: [null, null] 60 | } 61 | } 62 | } 63 | 64 | // Add the slug and name definitions to chartbuilder 65 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 66 | } 67 | ]) 68 | 69 | .controller(module.slug + 'Controller', [ 70 | '$scope', 71 | 'chartbuilderData', 72 | 'chartbuilderModuleRegistry', 73 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 74 | // Localize the datastore for the view 75 | $scope.dataStore = chartbuilderData; 76 | 77 | // Initialize the data -- store sample data and set structure 78 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 79 | } 80 | ]); 81 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/historicalBarChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [{ 3 | "key": "Quantity", 4 | "bar": true, 5 | "values": [ 6 | [ 1136005200000, 1271000.0], 7 | [ 1138683600000, 1271000.0], 8 | [ 1141102800000, 1271000.0], 9 | [ 1143781200000, 0], 10 | [ 1146369600000, 0], 11 | [ 1149048000000, 0], 12 | [ 1151640000000, 0], 13 | [ 1154318400000, 0], 14 | [ 1156996800000, 0], 15 | [ 1159588800000, 3899486.0], 16 | [ 1162270800000, 3899486.0], 17 | [ 1164862800000, 3899486.0], 18 | [ 1167541200000, 3564700.0], 19 | [ 1170219600000, 3564700.0], 20 | [ 1172638800000, 3564700.0], 21 | [ 1175313600000, 2648493.0], 22 | [ 1177905600000, 2648493.0], 23 | [ 1180584000000, 2648493.0] 24 | ] 25 | }] 26 | }) 27 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/historicalBarChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the historical bar chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Historical Bar Chart', 8 | slug: 'historicalBarChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.historicalBarChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'timestamp', 'type': 'number' }, { 'key': 'value', 'type': 'number' }], 44 | template: template, 45 | meta: { 46 | title: module.name, 47 | subtitle: 'Subtitle for a historical bar chart', 48 | caption: '1a. Edit a caption for the graph', 49 | }, 50 | options: { 51 | chart: { 52 | type: module.slug, 53 | height: 600, 54 | x: function(d){return d[0];}, 55 | y: function(d){return d[1]/100000;}, 56 | valueFormat: function(d) { 57 | return d3.format(',.1f')(d); 58 | }, 59 | xAxis: { 60 | axisLabel: 'X Axis', 61 | tickFormat: function(d) { 62 | return d3.time.format('%x')(new Date(d)); 63 | }, 64 | rotateLabels: 50 65 | }, 66 | yAxis: { 67 | axisLabel: 'Y Axis', 68 | axisLabelDistance: 35, 69 | tickFormat: function(d) { 70 | return d3.format(',.1f')(d); 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | // Add the slug and name definitions to chartbuilder 78 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 79 | } 80 | ]) 81 | 82 | .controller(module.slug + 'Controller', [ 83 | '$scope', 84 | 'chartbuilderData', 85 | 'chartbuilderModuleRegistry', 86 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 87 | // Localize the datastore for the view 88 | $scope.dataStore = chartbuilderData; 89 | 90 | // Initialize the data -- store sample data and set structure 91 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 92 | } 93 | ]); 94 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/lineChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [{ 3 | "key": "Price", 4 | "area": true, 5 | "values": [ [ 1136005200000 , 71.89] , [ 1138683600000 , 75.51] , [ 1141102800000 , 68.49] , [ 1143781200000 , 62.72] , [ 1146369600000 , 70.39] , [ 1149048000000 , 59.77] , [ 1151640000000 , 57.27] , [ 1154318400000 , 67.96] , [ 1156996800000 , 67.85] , [ 1159588800000 , 76.98] , [ 1162270800000 , 81.08] , [ 1164862800000 , 91.66] , [ 1167541200000 , 84.84] , [ 1170219600000 , 85.73] , [ 1172638800000 , 84.61] , [ 1175313600000 , 92.91] , [ 1177905600000 , 99.8] , [ 1180584000000 , 121.191] , [ 1183176000000 , 122.04] , [ 1185854400000 , 131.76] , [ 1188532800000 , 138.48] , [ 1191124800000 , 153.47] , [ 1193803200000 , 189.95] , [ 1196398800000 , 182.22] , [ 1199077200000 , 198.08] , [ 1201755600000 , 135.36] , [ 1204261200000 , 125.02] , [ 1206936000000 , 143.5] , [ 1209528000000 , 173.95] , [ 1212206400000 , 188.75] , [ 1214798400000 , 167.44] , [ 1217476800000 , 158.95] , [ 1220155200000 , 169.53] , [ 1222747200000 , 113.66] , [ 1225425600000 , 107.59] , [ 1228021200000 , 92.67] , [ 1230699600000 , 85.35] , [ 1233378000000 , 90.13] , [ 1235797200000 , 89.31] , [ 1238472000000 , 105.12] , [ 1241064000000 , 125.83] , [ 1243742400000 , 135.81] , [ 1246334400000 , 142.43] , [ 1249012800000 , 163.39] , [ 1251691200000 , 168.21] , [ 1254283200000 , 185.35] , [ 1256961600000 , 188.5] , [ 1259557200000 , 199.91] , [ 1262235600000 , 210.732] , [ 1264914000000 , 192.063] , [ 1267333200000 , 204.62] , [ 1270008000000 , 235.0] , [ 1272600000000 , 261.09] , [ 1275278400000 , 256.88] , [ 1277870400000 , 251.53] , [ 1280548800000 , 257.25] , [ 1283227200000 , 243.1] , [ 1285819200000 , 283.75] , [ 1288497600000 , 300.98] , [ 1291093200000 , 311.15] , [ 1293771600000 , 322.56] , [ 1296450000000 , 339.32] , [ 1298869200000 , 353.21] , [ 1301544000000 , 348.5075] , [ 1304136000000 , 350.13] , [ 1306814400000 , 347.83] , [ 1309406400000 , 335.67] , [ 1312084800000 , 390.48] , [ 1314763200000 , 384.83] , [ 1317355200000 , 381.32] , [ 1320033600000 , 404.78] , [ 1322629200000 , 382.2] , [ 1325307600000 , 405.0] , [ 1327986000000 , 456.48] , [ 1330491600000 , 542.44] , [ 1333166400000 , 599.55] , [ 1335758400000 , 583.98] ] 6 | }] 7 | }) 8 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/lineChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the lineChart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Line Chart', 8 | slug: 'lineChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.lineChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'x', 'type': 'number' }, { 'key': 'y', 'type': 'number' }], 44 | template: template, 45 | meta: { 46 | title: module.name, 47 | subtitle: 'Subtitle for a line chart', 48 | caption: '1a. Edit a caption for the graph', 49 | }, 50 | options: { 51 | chart: { 52 | type: module.slug, 53 | height: 600, 54 | x: 'function:x/y', 55 | y: 'function:key/y', 56 | forceX: [null, null], 57 | forceY: [null, null], 58 | useVoronoi: false 59 | } 60 | } 61 | } 62 | 63 | // Add the slug and name definitions to chartbuilder 64 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 65 | } 66 | ]) 67 | 68 | .controller(module.slug + 'Controller', [ 69 | '$scope', 70 | 'chartbuilderData', 71 | 'chartbuilderModuleRegistry', 72 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 73 | // Localize the datastore for the view 74 | $scope.dataStore = chartbuilderData; 75 | 76 | // Initialize the data -- store sample data and set structure 77 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 78 | } 79 | ]); 80 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/lineWithFocusChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [ 3 | { 4 | "key": "Quantity" , 5 | "bar": "true", 6 | "values": [ [ 1136005200000 , 1271000.0] , [ 1138683600000 , 1271000.0] , [ 1141102800000 , 1271000.0] , [ 1143781200000 , 0] , [ 1146369600000 , 0] , [ 1149048000000 , 0] , [ 1151640000000 , 0] , [ 1154318400000 , 0] , [ 1156996800000 , 0] , [ 1159588800000 , 3899486.0] , [ 1162270800000 , 3899486.0] , [ 1164862800000 , 3899486.0] , [ 1167541200000 , 3564700.0] , [ 1170219600000 , 3564700.0] , [ 1172638800000 , 3564700.0] , [ 1175313600000 , 2648493.0] , [ 1177905600000 , 2648493.0] , [ 1180584000000 , 2648493.0] , [ 1183176000000 , 2522993.0] , [ 1185854400000 , 2522993.0] , [ 1188532800000 , 2522993.0] , [ 1191124800000 , 2906501.0] , [ 1193803200000 , 2906501.0] , [ 1196398800000 , 2906501.0] , [ 1199077200000 , 2206761.0] , [ 1201755600000 , 2206761.0] , [ 1204261200000 , 2206761.0] , [ 1206936000000 , 2287726.0] , [ 1209528000000 , 2287726.0] , [ 1212206400000 , 2287726.0] , [ 1214798400000 , 2732646.0] , [ 1217476800000 , 2732646.0] , [ 1220155200000 , 2732646.0] , [ 1222747200000 , 2599196.0] , [ 1225425600000 , 2599196.0] , [ 1228021200000 , 2599196.0] , [ 1230699600000 , 1924387.0] , [ 1233378000000 , 1924387.0] , [ 1235797200000 , 1924387.0] , [ 1238472000000 , 1756311.0] , [ 1241064000000 , 1756311.0] , [ 1243742400000 , 1756311.0] , [ 1246334400000 , 1743470.0] , [ 1249012800000 , 1743470.0] , [ 1251691200000 , 1743470.0] , [ 1254283200000 , 1519010.0] , [ 1256961600000 , 1519010.0] , [ 1259557200000 , 1519010.0] , [ 1262235600000 , 1591444.0] , [ 1264914000000 , 1591444.0] , [ 1267333200000 , 1591444.0] , [ 1270008000000 , 1543784.0] , [ 1272600000000 , 1543784.0] , [ 1275278400000 , 1543784.0] , [ 1277870400000 , 1309915.0] , [ 1280548800000 , 1309915.0] , [ 1283227200000 , 1309915.0] , [ 1285819200000 , 1331875.0] , [ 1288497600000 , 1331875.0] , [ 1291093200000 , 1331875.0] , [ 1293771600000 , 1331875.0] , [ 1296450000000 , 1154695.0] , [ 1298869200000 , 1154695.0] , [ 1301544000000 , 1194025.0] , [ 1304136000000 , 1194025.0] , [ 1306814400000 , 1194025.0] , [ 1309406400000 , 1194025.0] , [ 1312084800000 , 1194025.0] , [ 1314763200000 , 1244525.0] , [ 1317355200000 , 475000.0] , [ 1320033600000 , 475000.0] , [ 1322629200000 , 475000.0] , [ 1325307600000 , 690033.0] , [ 1327986000000 , 690033.0] , [ 1330491600000 , 690033.0] , [ 1333166400000 , 514733.0] , [ 1335758400000 , 514733.0]] 7 | }, 8 | { 9 | "key": "Price" , 10 | "values": [ [ 1136005200000 , 71.89] , [ 1138683600000 , 75.51] , [ 1141102800000 , 68.49] , [ 1143781200000 , 62.72] , [ 1146369600000 , 70.39] , [ 1149048000000 , 59.77] , [ 1151640000000 , 57.27] , [ 1154318400000 , 67.96] , [ 1156996800000 , 67.85] , [ 1159588800000 , 76.98] , [ 1162270800000 , 81.08] , [ 1164862800000 , 91.66] , [ 1167541200000 , 84.84] , [ 1170219600000 , 85.73] , [ 1172638800000 , 84.61] , [ 1175313600000 , 92.91] , [ 1177905600000 , 99.8] , [ 1180584000000 , 121.191] , [ 1183176000000 , 122.04] , [ 1185854400000 , 131.76] , [ 1188532800000 , 138.48] , [ 1191124800000 , 153.47] , [ 1193803200000 , 189.95] , [ 1196398800000 , 182.22] , [ 1199077200000 , 198.08] , [ 1201755600000 , 135.36] , [ 1204261200000 , 125.02] , [ 1206936000000 , 143.5] , [ 1209528000000 , 173.95] , [ 1212206400000 , 188.75] , [ 1214798400000 , 167.44] , [ 1217476800000 , 158.95] , [ 1220155200000 , 169.53] , [ 1222747200000 , 113.66] , [ 1225425600000 , 107.59] , [ 1228021200000 , 92.67] , [ 1230699600000 , 85.35] , [ 1233378000000 , 90.13] , [ 1235797200000 , 89.31] , [ 1238472000000 , 105.12] , [ 1241064000000 , 125.83] , [ 1243742400000 , 135.81] , [ 1246334400000 , 142.43] , [ 1249012800000 , 163.39] , [ 1251691200000 , 168.21] , [ 1254283200000 , 185.35] , [ 1256961600000 , 188.5] , [ 1259557200000 , 199.91] , [ 1262235600000 , 210.732] , [ 1264914000000 , 192.063] , [ 1267333200000 , 204.62] , [ 1270008000000 , 235.0] , [ 1272600000000 , 261.09] , [ 1275278400000 , 256.88] , [ 1277870400000 , 251.53] , [ 1280548800000 , 257.25] , [ 1283227200000 , 243.1] , [ 1285819200000 , 283.75] , [ 1288497600000 , 300.98] , [ 1291093200000 , 311.15] , [ 1293771600000 , 322.56] , [ 1296450000000 , 339.32] , [ 1298869200000 , 353.21] , [ 1301544000000 , 348.5075] , [ 1304136000000 , 350.13] , [ 1306814400000 , 347.83] , [ 1309406400000 , 335.67] , [ 1312084800000 , 390.48] , [ 1314763200000 , 384.83] , [ 1317355200000 , 381.32] , [ 1320033600000 , 404.78] , [ 1322629200000 , 382.2] , [ 1325307600000 , 405.0] , [ 1327986000000 , 456.48] , [ 1330491600000 , 542.44] , [ 1333166400000 , 599.55] , [ 1335758400000 , 583.98] ] 11 | } 12 | ] 13 | }) 14 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/lineWithFocusChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the lineWithFocusChart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Line With Focus Chart', 8 | slug: 'lineWithFocusChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.lineWithFocusChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'x', 'type': 'number' }, { 'key': 'y', 'type': 'number' }], 44 | template: template, 45 | meta: { 46 | title: module.name, 47 | subtitle: 'Subtitle for a line chart', 48 | caption: '1a. Edit a caption for the graph', 49 | }, 50 | options: { 51 | chart: { 52 | type: module.slug, 53 | height: 600, 54 | forceX: [null, null], 55 | forceY: [null, null], 56 | xAxis: { 57 | tickFormat: 'function:year' 58 | } 59 | } 60 | } 61 | } 62 | 63 | // Add the slug and name definitions to chartbuilder 64 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 65 | } 66 | ]) 67 | 68 | .controller(module.slug + 'Controller', [ 69 | '$scope', 70 | 'chartbuilderData', 71 | 'chartbuilderModuleRegistry', 72 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 73 | // Localize the datastore for the view 74 | $scope.dataStore = chartbuilderData; 75 | 76 | // Initialize the data -- store sample data and set structure 77 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 78 | } 79 | ]); 80 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/multiBarChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [ 3 | { 4 | "key": "Series 1", 5 | "values": [ 6 | { "x": "A", "y": -29.765957771107 }, 7 | { "x": "B", "y": 0 }, 8 | { "x": "C", "y": 32.807804682612 }, 9 | { "x": "D", "y": 196.45946739256 }, 10 | { "x": "E", "y": 0.19434030906893 }, 11 | { "x": "F", "y": -98.079782601442 }, 12 | { "x": "G", "y": -13.925743130903 }, 13 | { "x": "H", "y": -5.1387322875705 } 14 | ] 15 | }, 16 | { 17 | "key": "Series 2", 18 | "values": [ 19 | { "x": "A", "y": -5.1387322875705 }, 20 | { "x": "B", "y": -13.925743130903 }, 21 | { "x": "C", "y": -98.079782601442 }, 22 | { "x": "D", "y": 0.19434030906893 }, 23 | { "x": "E", "y": 196.45946739256 }, 24 | { "x": "F", "y": 32.807804682612 }, 25 | { "x": "G", "y": 0 }, 26 | { "x": "H", "y": -29.765957771107 } 27 | ] 28 | }, 29 | { 30 | "key": "Series 3", 31 | "values": [ 32 | { "x": "A", "y": 196.45946739256 }, 33 | { "x": "B", "y": -98.079782601442 }, 34 | { "x": "C", "y": 0 }, 35 | { "x": "D", "y": -13.925743130903 }, 36 | { "x": "E", "y": -5.1387322875705 }, 37 | { "x": "F", "y": -29.765957771107 }, 38 | { "x": "G", "y": 32.807804682612 }, 39 | { "x": "H", "y": 0.19434030906893 } 40 | ] 41 | }] 42 | }); 43 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/multiBarChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the multi bar chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Multi Bar Chart', 8 | slug: 'multiBarChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.multiBarChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'x', 'type': 'text' }, { 'key': 'y', 'type': 'number' }], 44 | template: template, 45 | meta: { 46 | title: module.name, 47 | subtitle: 'Subtitle for a multi bar chart', 48 | caption: '1a. Edit a caption for the graph', 49 | }, 50 | options: { 51 | chart: { 52 | type: module.slug, 53 | height: 600, 54 | clipEdge: true, 55 | forceY: [null, null], 56 | forceX: [null, null], 57 | x: 'function:x/y', 58 | y: 'function:key/y', 59 | tooltip: 'function:multiBarChart', 60 | wrapLabels: true 61 | } 62 | } 63 | } 64 | 65 | // Add the slug and name definitions to chartbuilder 66 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 67 | } 68 | ]) 69 | 70 | .controller(module.slug + 'Controller', [ 71 | '$scope', 72 | 'chartbuilderData', 73 | 'chartbuilderModuleRegistry', 74 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 75 | // Localize the datastore for the view 76 | $scope.dataStore = chartbuilderData; 77 | 78 | // Initialize the data -- store sample data and set structure 79 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 80 | } 81 | ]); 82 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/multiBarHorizontalChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [ 3 | { 4 | "key": "Series1", 5 | "color": "#d62728", 6 | "values": [{ 7 | "label" : "Group A" , 8 | "value" : -1.8746444827653 9 | }, 10 | { 11 | "label" : "Group B" , 12 | "value" : -8.0961543492239 13 | }, 14 | { 15 | "label" : "Group C" , 16 | "value" : -0.57072943117674 17 | }, 18 | { 19 | "label" : "Group D" , 20 | "value" : -2.4174010336624 21 | }, 22 | { 23 | "label" : "Group E" , 24 | "value" : -0.72009071426284 25 | }, 26 | { 27 | "label" : "Group F" , 28 | "value" : -0.77154485523777 29 | }, 30 | { 31 | "label" : "Group G" , 32 | "value" : -0.90152097798131 33 | }, 34 | { 35 | "label" : "Group H" , 36 | "value" : -0.91445417330854 37 | }, 38 | { 39 | "label" : "Group I" , 40 | "value" : -0.055746319141851 41 | } 42 | ] 43 | }, 44 | { 45 | "key": "Series2", 46 | "color": "#1f77b4", 47 | "values": [ 48 | { 49 | "label" : "Group A" , 50 | "value" : 25.307646510375 51 | } , 52 | { 53 | "label" : "Group B" , 54 | "value" : 16.756779544553 55 | } , 56 | { 57 | "label" : "Group C" , 58 | "value" : 18.451534877007 59 | } , 60 | { 61 | "label" : "Group D" , 62 | "value" : 8.6142352811805 63 | } , 64 | { 65 | "label" : "Group E" , 66 | "value" : 7.8082472075876 67 | } , 68 | { 69 | "label" : "Group F" , 70 | "value" : 5.259101026956 71 | } , 72 | { 73 | "label" : "Group G" , 74 | "value" : 0.30947953487127 75 | } , 76 | { 77 | "label" : "Group H" , 78 | "value" : 0 79 | } , 80 | { 81 | "label" : "Group I" , 82 | "value" : 0 83 | } 84 | ] 85 | } 86 | ] 87 | }); 88 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/multiBarHorizontalChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the multi bar horizontal chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Multi Bar Horizontal Chart', 8 | slug: 'multiBarHorizontalChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 17 | 18 | angular 19 | 20 | .module('chartbuilder.nvd3.multiBarHorizontalChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 21 | 22 | /** 23 | * Add this module's state to ui-router routes 24 | */ 25 | .config(['$stateProvider', function($stateProvider) { 26 | $stateProvider.state('chartbuilder.' + module.slug, { 27 | url: '/' + module.slug, 28 | views: { 29 | 'graph': { 30 | template: template, 31 | controller: module.slug + 'Controller' 32 | } 33 | } 34 | }); 35 | }]) 36 | 37 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 38 | var moduleOpts = {}; 39 | moduleOpts[module.name] = { 40 | name: module.name, 41 | slug: module.slug, 42 | data: module.data, 43 | dataFormat: [{ 'key': 'label', 'type': 'text' }, { 'key': 'value', 'type': 'number' }], 44 | template: template, 45 | meta: { 46 | title: module.name, 47 | subtitle: 'Subtitle for a bar chart', 48 | caption: '1a. Edit a caption for the graph', 49 | }, 50 | options: { 51 | chart: { 52 | type: module.slug, 53 | height: 600, 54 | x: 'function:label/value', 55 | y: 'function:label/value', 56 | showValues: true, 57 | clipEdge: true, 58 | forceY: [null, null] 59 | } 60 | } 61 | } 62 | 63 | // Add the slug and name definitions to chartbuilder 64 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 65 | } 66 | ]) 67 | 68 | .controller(module.slug + 'Controller', [ 69 | '$scope', 70 | 'chartbuilderData', 71 | 'chartbuilderModuleRegistry', 72 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 73 | // Localize the datastore for the view 74 | $scope.dataStore = chartbuilderData; 75 | 76 | // Initialize the data -- store sample data and set structure 77 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 78 | } 79 | ]); 80 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/pieChart/data.js: -------------------------------------------------------------------------------- 1 | define({ 2 | "exampleData": [{ 3 | "key": "Series 1", 4 | "values": [ 5 | { "key": "One", "y": 5 }, 6 | { "key": "Two", "y": 2 }, 7 | { "key": "Three", "y": 9 }, 8 | { "key": "Four", "y": 7 }, 9 | { "key": "Five", "y": 4 }, 10 | { "key": "Six", "y": 3 }, 11 | { "key": "Seven", "y": .5 } 12 | ] 13 | }] 14 | }) 15 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/pieChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the pie chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var module = { 7 | name: 'Pie Chart', 8 | slug: 'pieChart', 9 | data: require('./data') 10 | }; 11 | 12 | var template = [''].join(''); 18 | 19 | angular 20 | 21 | .module('chartbuilder.nvd3.pieChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 22 | 23 | /** 24 | * Add this module's state to ui-router routes 25 | */ 26 | .config(['$stateProvider', function($stateProvider) { 27 | $stateProvider.state('chartbuilder.' + module.slug, { 28 | url: '/' + module.slug, 29 | views: { 30 | 'graph': { 31 | template: template, 32 | controller: module.slug + 'Controller' 33 | } 34 | } 35 | }); 36 | }]) 37 | 38 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 39 | var moduleOpts = {}; 40 | moduleOpts[module.name] = { 41 | name: module.name, 42 | slug: module.slug, 43 | data: module.data, 44 | dataFormat: [{ 'key': 'key', 'type': 'text' }, { 'key': 'y', 'type': 'number' } ], 45 | template: template, 46 | meta: { 47 | title: module.name, 48 | subtitle: 'Subtitle for a pie chart', 49 | caption: '1a. Edit a caption for the pie chart', 50 | }, 51 | options: { 52 | chart: { 53 | type: module.slug, 54 | height: 600, 55 | x: 'function:key/value', 56 | y: 'function:key/y' 57 | } 58 | } 59 | } 60 | 61 | // Add the slug and name definitions to chartbuilder 62 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 63 | } 64 | ]) 65 | 66 | .controller(module.slug + 'Controller', [ 67 | '$scope', 68 | 'chartbuilderData', 69 | 'chartbuilderModuleRegistry', 70 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 71 | // Localize the datastore for the view 72 | $scope.dataStore = chartbuilderData; 73 | 74 | // Initialize the data -- store sample data and set structure 75 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 76 | } 77 | ]); 78 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/scatterChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the scatter chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var d3 = require('d3'); 7 | 8 | var module = { 9 | name: 'Scatter Chart', 10 | slug: 'scatterChart' 11 | }; 12 | 13 | var template = [''].join(''); 18 | 19 | angular 20 | 21 | .module('chartbuilder.nvd3.scatterChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 22 | 23 | /** 24 | * Add this module's state to ui-router routes 25 | */ 26 | .config(['$stateProvider', function($stateProvider) { 27 | $stateProvider.state('chartbuilder.' + module.slug, { 28 | url: '/' + module.slug, 29 | views: { 30 | 'graph': { 31 | template: template, 32 | controller: module.slug + 'Controller' 33 | } 34 | } 35 | }); 36 | }]) 37 | 38 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 39 | var shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'], 40 | data = generateData(4, 10); 41 | function generateData(groups, points) { 42 | var data = [], 43 | random = d3.random.normal(); 44 | 45 | for (var i = 0; i < groups; i++) { 46 | data.push({ 47 | key: 'Group ' + i, 48 | values: [] 49 | }); 50 | 51 | for (var j = 0; j < points; j++) { 52 | data[i].values.push({ 53 | x: random(), 54 | y: random(), 55 | size: Math.random(), 56 | shape: shapes[j % 6] 57 | }); 58 | } 59 | } 60 | return data; 61 | } 62 | var moduleOpts = {}; 63 | moduleOpts[module.name] = { 64 | name: module.name, 65 | slug: module.slug, 66 | data: { exampleData: data }, 67 | dataFormat: [{ 'key': 'x', 'type': 'number' }, { 'key': 'y', 'type': 'number' }, { 'key': 'size', 'type': 'number' }, { 'key': 'shape', 'type': 'text' }], 68 | shapes: shapes, 69 | template: template, 70 | meta: { 71 | title: module.name, 72 | subtitle: 'Subtitle for a scatter chart', 73 | caption: '1a. Edit a caption for the graph', 74 | }, 75 | options: { 76 | chart: { 77 | type: module.slug, 78 | height: 600, 79 | scatter: { 80 | onlyCircles: false 81 | }, 82 | showDistX: true, 83 | showDistY: true, 84 | tooltipContent: function(key) { 85 | return '

' + key + '

'; 86 | }, 87 | forceX: [null, null], 88 | forceY: [null, null], 89 | xAxis: { 90 | axisLabel: 'X Axis', 91 | tickFormat: function(d) { 92 | return d3.format('.02f')(d); 93 | } 94 | }, 95 | yAxis: { 96 | axisLabel: 'Y Axis', 97 | tickFormat: function(d) { 98 | return d3.format('.02f')(d); 99 | }, 100 | axisLabelDistance: 30 101 | } 102 | } 103 | } 104 | } 105 | 106 | // Add the slug and name definitions to chartbuilder 107 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 108 | } 109 | ]) 110 | 111 | .controller(module.slug + 'Controller', [ 112 | '$scope', 113 | 'chartbuilderData', 114 | 'chartbuilderModuleRegistry', 115 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 116 | // Localize the datastore for the view 117 | $scope.dataStore = chartbuilderData; 118 | 119 | // Initialize the data -- store sample data and set structure 120 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 121 | } 122 | ]); 123 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/scatterPlusLineChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the scatter plus line chart nvd3-directive 3 | */ 4 | "use strict"; 5 | 6 | var d3 = require('d3'); 7 | 8 | var module = { 9 | name: 'Scatter Plus Line Chart', 10 | slug: 'scatterPlusLineChart' 11 | }; 12 | 13 | var template = [''].join(''); 18 | 19 | angular 20 | 21 | .module('chartbuilder.nvd3.scatterPlusLineChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 22 | 23 | /** 24 | * Add this module's state to ui-router routes 25 | */ 26 | .config(['$stateProvider', function($stateProvider) { 27 | $stateProvider.state('chartbuilder.' + module.slug, { 28 | url: '/' + module.slug, 29 | views: { 30 | 'graph': { 31 | template: template, 32 | controller: module.slug + 'Controller' 33 | } 34 | } 35 | }); 36 | }]) 37 | 38 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 39 | var shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'], 40 | data = generateData(4, 10); 41 | function generateData(groups, points) { 42 | var data = [], 43 | random = d3.random.normal(); 44 | 45 | for (var i = 0; i < groups; i++) { 46 | data.push({ 47 | key: 'Group ' + i, 48 | values: [], 49 | slope: Math.random() - .01, 50 | intercept: Math.random() - .5 51 | }); 52 | 53 | for (var j = 0; j < points; j++) { 54 | data[i].values.push({ 55 | x: random(), 56 | y: random(), 57 | size: Math.random(), 58 | shape: shapes[j % 6] 59 | }); 60 | } 61 | } 62 | return data; 63 | } 64 | var moduleOpts = {}; 65 | moduleOpts[module.name] = { 66 | name: module.name, 67 | slug: module.slug, 68 | data: { exampleData: data }, 69 | dataFormat: [{ 'key': 'x', 'type': 'number' }, { 'key': 'y', 'type': 'number' }, { 'key': 'size', 'type': 'number' }, { 'key': 'shape', 'type': 'text' }], 70 | shapes: shapes, 71 | template: template, 72 | meta: { 73 | title: module.name, 74 | subtitle: 'Subtitle for a scatter plus line chart', 75 | caption: '1a. Edit a caption for the graph', 76 | }, 77 | options: { 78 | chart: { 79 | type: module.slug, 80 | height: 600, 81 | scatter: { 82 | onlyCircles: false 83 | }, 84 | showDistX: true, 85 | showDistY: true, 86 | forceX: [null, null], 87 | forceY: [null, null], 88 | tooltipContent: function(key) { 89 | return '

' + key + '

'; 90 | }, 91 | } 92 | } 93 | } 94 | 95 | // Add the slug and name definitions to chartbuilder 96 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 97 | } 98 | ]) 99 | 100 | .controller(module.slug + 'Controller', [ 101 | '$scope', 102 | 'chartbuilderData', 103 | 'chartbuilderModuleRegistry', 104 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 105 | // Localize the datastore for the view 106 | $scope.dataStore = chartbuilderData; 107 | 108 | // Initialize the data -- store sample data and set structure 109 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 110 | } 111 | ]); 112 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/nvd3-modules/stackedAreaChart/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Modular version of the stacked area chart nvd3-directive 3 | */ 4 | 'use strict'; 5 | 6 | var d3 = require('d3'); 7 | 8 | var module = { 9 | name: 'Stacked Area Chart', 10 | slug: 'stackedAreaChart', 11 | data: require('./data') 12 | }; 13 | 14 | var template = [''].join(''); 19 | 20 | angular 21 | 22 | .module('chartbuilder.nvd3.stackedAreaChart', ['chartbuilderServices', 'chartbuilder.nvd3']) 23 | 24 | /** 25 | * Add this module's state to ui-router routes 26 | */ 27 | .config(['$stateProvider', function($stateProvider) { 28 | $stateProvider.state('chartbuilder.' + module.slug, { 29 | url: '/' + module.slug, 30 | views: { 31 | 'graph': { 32 | template: template, 33 | controller: module.slug + 'Controller' 34 | } 35 | } 36 | }); 37 | }]) 38 | 39 | .run(['chartbuilderModuleRegistry', function(chartbuilderModuleRegistry) { 40 | var moduleOpts = {}; 41 | moduleOpts[module.name] = { 42 | name: module.name, 43 | slug: module.slug, 44 | data: module.data, 45 | dataFormat: [{ 'key': 'text', 'values': [{ 'key': 0, 'type': 'number' }, { 'key': 1, 'type': 'number' }] }], 46 | template: template, 47 | meta: { 48 | title: module.name, 49 | subtitle: 'Subtitle for a stacked area chart', 50 | caption: '1a. Edit a caption for the graph', 51 | }, 52 | options: { 53 | chart: { 54 | type: module.slug, 55 | height: 600, 56 | x: function(d){return d[0];}, 57 | y: function(d){return d[1];}, 58 | useVoronoi: false, 59 | clipEdge: true, 60 | useInteractiveGuideline: true, 61 | xAxis: { 62 | showMaxMin: false, 63 | tickFormat: function(d) { 64 | return d3.time.format('%x')(new Date(d)); 65 | } 66 | }, 67 | yAxis: { 68 | tickFormat: function(d) { 69 | return d3.format(',.2f')(d); 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | // Add the slug and name definitions to chartbuilder 77 | angular.extend(chartbuilderModuleRegistry, moduleOpts); 78 | } 79 | ]) 80 | 81 | .controller(module.slug + 'Controller', [ 82 | '$scope', 83 | 'chartbuilderData', 84 | 'chartbuilderModuleRegistry', 85 | function($scope, chartbuilderData, chartbuilderModuleRegistry) { 86 | // Localize the datastore for the view 87 | $scope.dataStore = chartbuilderData; 88 | 89 | // Initialize the data -- store sample data and set structure 90 | chartbuilderData.init(chartbuilderModuleRegistry[module.name]); 91 | } 92 | ]); 93 | -------------------------------------------------------------------------------- /app/scripts/angular_modules/ui-sortable/sortable.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery UI Sortable plugin wrapper 3 | 4 | @param [ui-sortable] {object} Options to pass to $.fn.sortable() merged onto ui.config 5 | */ 6 | angular.module('ui.sortable', []) 7 | .value('uiSortableConfig',{}) 8 | .directive('uiSortable', [ 9 | 'uiSortableConfig', '$timeout', '$log', 10 | function(uiSortableConfig, $timeout, $log) { 11 | return { 12 | require: '?ngModel', 13 | link: function(scope, element, attrs, ngModel) { 14 | var savedNodes; 15 | 16 | function combineCallbacks(first,second){ 17 | if(second && (typeof second === 'function')) { 18 | return function(e, ui) { 19 | first(e, ui); 20 | second(e, ui); 21 | }; 22 | } 23 | return first; 24 | } 25 | 26 | var opts = {}; 27 | 28 | var callbacks = { 29 | receive: null, 30 | remove:null, 31 | start:null, 32 | stop:null, 33 | update:null 34 | }; 35 | 36 | angular.extend(opts, uiSortableConfig); 37 | 38 | if (ngModel) { 39 | 40 | // When we add or remove elements, we need the sortable to 'refresh' 41 | // so it can find the new/removed elements. 42 | scope.$watch(attrs.ngModel+'.length', function() { 43 | // Timeout to let ng-repeat modify the DOM 44 | $timeout(function() { 45 | // ensure that the jquery-ui-sortable widget instance 46 | // is still bound to the directive's element 47 | if (!!element.data('ui-sortable')) { 48 | element.sortable('refresh'); 49 | } 50 | }); 51 | }); 52 | 53 | callbacks.start = function(e, ui) { 54 | // Save the starting position of dragged item 55 | ui.item.sortable = { 56 | index: ui.item.index(), 57 | cancel: function () { 58 | ui.item.sortable._isCanceled = true; 59 | }, 60 | isCanceled: function () { 61 | return ui.item.sortable._isCanceled; 62 | }, 63 | _isCanceled: false 64 | }; 65 | }; 66 | 67 | callbacks.activate = function(/*e, ui*/) { 68 | // We need to make a copy of the current element's contents so 69 | // we can restore it after sortable has messed it up. 70 | // This is inside activate (instead of start) in order to save 71 | // both lists when dragging between connected lists. 72 | savedNodes = element.contents(); 73 | 74 | // If this list has a placeholder (the connected lists won't), 75 | // don't inlcude it in saved nodes. 76 | var placeholder = element.sortable('option','placeholder'); 77 | 78 | // placeholder.element will be a function if the placeholder, has 79 | // been created (placeholder will be an object). If it hasn't 80 | // been created, either placeholder will be false if no 81 | // placeholder class was given or placeholder.element will be 82 | // undefined if a class was given (placeholder will be a string) 83 | if (placeholder && placeholder.element && typeof placeholder.element === 'function') { 84 | var phElement = placeholder.element(); 85 | // workaround for jquery ui 1.9.x, 86 | // not returning jquery collection 87 | if (!phElement.jquery) { 88 | phElement = angular.element(phElement); 89 | } 90 | 91 | // exact match with the placeholder's class attribute to handle 92 | // the case that multiple connected sortables exist and 93 | // the placehoilder option equals the class of sortable items 94 | var excludes = element.find('[class="' + phElement.attr('class') + '"]'); 95 | 96 | savedNodes = savedNodes.not(excludes); 97 | } 98 | }; 99 | 100 | callbacks.update = function(e, ui) { 101 | // Save current drop position but only if this is not a second 102 | // update that happens when moving between lists because then 103 | // the value will be overwritten with the old value 104 | if(!ui.item.sortable.received) { 105 | ui.item.sortable.dropindex = ui.item.index(); 106 | ui.item.sortable.droptarget = ui.item.parent(); 107 | 108 | // Cancel the sort (let ng-repeat do the sort for us) 109 | // Don't cancel if this is the received list because it has 110 | // already been canceled in the other list, and trying to cancel 111 | // here will mess up the DOM. 112 | element.sortable('cancel'); 113 | } 114 | 115 | // Put the nodes back exactly the way they started (this is very 116 | // important because ng-repeat uses comment elements to delineate 117 | // the start and stop of repeat sections and sortable doesn't 118 | // respect their order (even if we cancel, the order of the 119 | // comments are still messed up). 120 | if (element.sortable('option','helper') === 'clone') { 121 | // restore all the savedNodes except .ui-sortable-helper element 122 | // (which is placed last). That way it will be garbage collected. 123 | savedNodes = savedNodes.not(savedNodes.last()); 124 | } 125 | savedNodes.appendTo(element); 126 | 127 | // If received is true (an item was dropped in from another list) 128 | // then we add the new item to this list otherwise wait until the 129 | // stop event where we will know if it was a sort or item was 130 | // moved here from another list 131 | if(ui.item.sortable.received && !ui.item.sortable.isCanceled()) { 132 | scope.$apply(function () { 133 | ngModel.$modelValue.splice(ui.item.sortable.dropindex, 0, 134 | ui.item.sortable.moved); 135 | }); 136 | } 137 | }; 138 | 139 | callbacks.stop = function(e, ui) { 140 | // If the received flag hasn't be set on the item, this is a 141 | // normal sort, if dropindex is set, the item was moved, so move 142 | // the items in the list. 143 | if(!ui.item.sortable.received && 144 | ('dropindex' in ui.item.sortable) && 145 | !ui.item.sortable.isCanceled()) { 146 | 147 | scope.$apply(function () { 148 | ngModel.$modelValue.splice( 149 | ui.item.sortable.dropindex, 0, 150 | ngModel.$modelValue.splice(ui.item.sortable.index, 1)[0]); 151 | }); 152 | } else { 153 | // if the item was not moved, then restore the elements 154 | // so that the ngRepeat's comment are correct. 155 | if((!('dropindex' in ui.item.sortable) || ui.item.sortable.isCanceled()) && element.sortable('option','helper') !== 'clone') { 156 | savedNodes.appendTo(element); 157 | } 158 | } 159 | }; 160 | 161 | callbacks.receive = function(e, ui) { 162 | // An item was dropped here from another list, set a flag on the 163 | // item. 164 | ui.item.sortable.received = true; 165 | }; 166 | 167 | callbacks.remove = function(e, ui) { 168 | // Remove the item from this list's model and copy data into item, 169 | // so the next list can retrive it 170 | if (!ui.item.sortable.isCanceled()) { 171 | scope.$apply(function () { 172 | ui.item.sortable.moved = ngModel.$modelValue.splice( 173 | ui.item.sortable.index, 1)[0]; 174 | }); 175 | } 176 | }; 177 | 178 | scope.$watch(attrs.uiSortable, function(newVal /*, oldVal*/) { 179 | // ensure that the jquery-ui-sortable widget instance 180 | // is still bound to the directive's element 181 | if (!!element.data('ui-sortable')) { 182 | angular.forEach(newVal, function(value, key) { 183 | if(callbacks[key]) { 184 | if( key === 'stop' ){ 185 | // call apply after stop 186 | value = combineCallbacks( 187 | value, function() { scope.$apply(); }); 188 | } 189 | // wrap the callback 190 | value = combineCallbacks(callbacks[key], value); 191 | } 192 | 193 | element.sortable('option', key, value); 194 | }); 195 | } 196 | }, true); 197 | 198 | angular.forEach(callbacks, function(value, key) { 199 | opts[key] = combineCallbacks(value, opts[key]); 200 | }); 201 | 202 | } else { 203 | $log.info('ui.sortable: ngModel not provided!', element); 204 | } 205 | 206 | // Create sortable 207 | element.sortable(opts); 208 | } 209 | }; 210 | } 211 | ]); 212 | -------------------------------------------------------------------------------- /app/scripts/directives/bsAffix.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | 5 | angular 6 | 7 | .module('chartbuilderDirectives') 8 | 9 | .directive('bsAffix', function($window, $location) { 10 | 11 | var checkPosition = function(instance, el, options) { 12 | 13 | var scrollTop = window.pageYOffset, 14 | scrollHeight = document.body.scrollHeight, 15 | position = jQuery(el[0]).offset(), 16 | height = jQuery(el[0]).height(), 17 | windowHeight = jQuery(window).height(), 18 | offsetTop = options.offsetTop * 1, 19 | offsetBottom = options.offsetBottom * 1, 20 | reset = 'affix affix-top affix-bottom', 21 | affix; 22 | 23 | if (instance.unpin !== null && (scrollTop + instance.unpin <= position.top)) { 24 | affix = false; 25 | } else if (windowHeight >= height) { 26 | affix = 'top'; 27 | } else if (offsetBottom && (height >= windowHeight - offsetBottom)) { 28 | affix = 'bottom'; 29 | } else if (offsetTop && scrollTop <= offsetTop) { 30 | affix = 'top'; 31 | } else { 32 | affix = false; 33 | } 34 | 35 | if (instance.affixed === affix) { 36 | return; 37 | } 38 | 39 | instance.affixed = affix; 40 | instance.unpin = affix === 'bottom' ? position.top - scrollTop : null; 41 | 42 | el.removeClass(reset).addClass('affix'); 43 | if (affix) { 44 | el.addClass('affix' + (affix ? '-' + affix : '')); 45 | } 46 | }; 47 | 48 | var checkCallbacks = function(scope, instance, element, attrs) { 49 | if (instance.affixed) { 50 | if (attrs.onUnaffix) { 51 | eval('scope.' + attrs.onUnaffix); 52 | } 53 | } 54 | else { 55 | if (attrs.onAffix) { 56 | eval('scope.' + attrs.onAffix); 57 | } 58 | } 59 | }; 60 | 61 | return { 62 | restrict: 'EA', 63 | link: function postLink(scope, element, attrs) { 64 | var instance = { 65 | unpin: null 66 | }; 67 | 68 | angular.element($window).bind('scroll', function() { 69 | checkPosition(instance, element, attrs); 70 | checkCallbacks(scope, instance, element, attrs); 71 | }); 72 | 73 | angular.element($window).bind('click', function() { 74 | setTimeout(function() { 75 | checkPosition(instance, element, attrs); 76 | checkCallbacks(scope, instance, element, attrs); 77 | }, 1); 78 | }); 79 | } 80 | }; 81 | 82 | }); 83 | -------------------------------------------------------------------------------- /app/scripts/directives/colors.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | 5 | angular 6 | 7 | .module('chartbuilderDirectives') 8 | 9 | .directive('chartbuilderColors', function () { 10 | return { 11 | restrict: 'EA', 12 | template: ['
', 13 | '', 25 | '', 26 | 27 | '', 28 | '', 29 | '
', 30 | 'use a color scale', 31 | 'pick colors for every item'].join(''), 32 | link: function(scope) { 33 | 34 | scope.addNewColor = function() { 35 | scope.chartbuilderData.colors.push('#FFFFFF'); 36 | }; 37 | 38 | scope.reverseColors = function() { 39 | scope.chartbuilderData.colors.reverse(); 40 | }; 41 | 42 | scope.customColors = function() { 43 | scope.chartbuilderData.options.customColors = true; 44 | }; 45 | 46 | } 47 | }; 48 | }); 49 | -------------------------------------------------------------------------------- /app/scripts/directives/data-input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | 5 | var d3 = require('d3'); 6 | 7 | angular 8 | 9 | .module('chartbuilderDirectives') 10 | 11 | .directive('structureDataInput', ['chartbuilderUtils', 'chartbuilderData', function(chartbuilderUtils, chartbuilderData) { 12 | return { 13 | restrict: 'EA', 14 | template: require('../../partials/data-forms/structure-data-input.html'), 15 | link: function(scope) { 16 | scope.dataGroupBox = {}; 17 | scope.newRow = {}; 18 | scope.newDataFile = {}; 19 | scope.singleSeriesData = {}; 20 | 21 | // Keep an empty new row for the input model 22 | scope.$watch('chartbuilderData.data', function(newval) { 23 | if (angular.isUndefined(chartbuilderData.dataFormat)) { 24 | return; 25 | } 26 | angular.forEach(newval, function(group, gidx) { 27 | scope.newRow[gidx] = {}; 28 | }); 29 | if (chartbuilderUtils.getType(chartbuilderData.dataFormat[0].values) === 'array') { 30 | scope.groupedData = chartbuilderData.data[0].values; 31 | scope.groupedFormat = chartbuilderData.dataFormat[0].values; 32 | } else { 33 | scope.groupedData = chartbuilderData.data; 34 | scope.groupedFormat = chartbuilderData.dataFormat; 35 | } 36 | }, true); 37 | 38 | // When data is pasted to the input text area, parse it for values 39 | scope.onPasteInputChanged = function(input, gidx) { 40 | scope.chartbuilderData.data[gidx].values = d3.csv.parse(input); 41 | scope.pasteInputToggle = false; 42 | }; 43 | 44 | // Append a new data row from the empty data model 45 | scope.addRow = function(gidx) { 46 | var validate = true; 47 | angular.forEach(scope.chartbuilderData.columnValues, function(type, key) { 48 | if (!_.has(scope.newRow[gidx], key) || scope.newRow[gidx][key] === null) { 49 | validate = false; 50 | } 51 | }); 52 | if (!validate) { 53 | return false; 54 | } 55 | scope.chartbuilderData.data[gidx].values.push(scope.newRow[gidx]); 56 | }; 57 | 58 | scope.addGroup = function() { 59 | if (!scope.newDataGroup) { 60 | return false; 61 | } 62 | chartbuilderData.addGroup(scope.newDataGroup); 63 | scope.newDataGroup = ''; 64 | }; 65 | 66 | scope.duplicateGroup = function() { 67 | if (!scope.newDataGroup) { 68 | return false; 69 | } 70 | chartbuilderData.duplicateGroup(scope.newDataGroup); 71 | scope.newDataGroup = ''; 72 | }; 73 | 74 | scope.removeRow = function(gidx, idx) { 75 | scope.chartbuilderData.data[gidx].values.splice(idx, 1); 76 | }; 77 | 78 | // This is just the callback from the file reader input. Parse and insert uploaded values 79 | scope.readFile = function(file, gidx) { 80 | scope.chartbuilderData.data[gidx].values = d3.csv.parse(file); 81 | }; 82 | 83 | // Download existing csv data 84 | scope.downloadCSV = function(gidx) { 85 | var csvText = d3.csv.format(scope.chartbuilderData.data[gidx].values); 86 | chartbuilderUtils.saveFile(csvText, scope.chartbuilderData.data[gidx].key + '.csv', 'text/csv'); 87 | }; 88 | } 89 | }; 90 | }]); 91 | -------------------------------------------------------------------------------- /app/scripts/directives/directives.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | require('./data-input'); 5 | require('./colors'); 6 | require('./bsAffix'); 7 | require('./edit-in-place'); 8 | require('./live-data-table'); 9 | require('./template-loader'); 10 | require('./save-images'); 11 | require('../angular_modules/chartbuilder-options/options'); 12 | require('../angular_modules/chartbuilder-options/options-constants'); 13 | require('../angular_modules/ui-sortable/sortable'); 14 | require('../../bower_components/angular-file-input/dist/angular-file-input'); 15 | require('../../bower_components/slugifier/angular-slugify'); 16 | -------------------------------------------------------------------------------- /app/scripts/directives/edit-in-place.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | 5 | angular 6 | 7 | .module('chartbuilderDirectives') 8 | 9 | .directive('editInPlace', function() { 10 | return { 11 | restrict: 'EA', 12 | scope: { 13 | value: '=', 14 | type: '@?' 15 | }, 16 | template: require('../../partials/data-forms/edit-in-place.html'), 17 | link: function(scope, element) { 18 | var inputElement = angular.element(element.children()[1]); 19 | 20 | element.addClass('edit-in-place'); 21 | 22 | scope.editing = false; 23 | 24 | scope.edit = function() { 25 | scope.editing = true; 26 | 27 | element.addClass('active'); 28 | inputElement[0].focus(); 29 | }; 30 | 31 | inputElement.bind('keydown keypress', function(event) { 32 | if (event.which === 13) { 33 | if (!scope.value.toString().length) { 34 | element.addClass('empty'); 35 | } else { 36 | element.removeClass('empty'); 37 | } 38 | scope.editing = false; 39 | element.removeClass('active'); 40 | } 41 | }); 42 | 43 | inputElement.bind('blur', function() { 44 | if (!scope.value.toString().length) { 45 | element.addClass('empty'); 46 | } else { 47 | element.removeClass('empty'); 48 | } 49 | scope.editing = false; 50 | element.removeClass('active'); 51 | }); 52 | } 53 | }; 54 | }); 55 | -------------------------------------------------------------------------------- /app/scripts/directives/input-group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | 5 | .module('chartbuilderDirectives') 6 | 7 | .directive('inputGroup', function () { 8 | return { 9 | restrict: 'EA', 10 | transclude: true, 11 | scope: { 12 | label: '@' // Gets the string contents of the `label` attribute. 13 | }, 14 | template: ['
', 15 | '', 16 | '{{ label }}', 17 | '', 18 | '', 19 | '
'].join(''), 20 | }; 21 | }); 22 | -------------------------------------------------------------------------------- /app/scripts/directives/live-data-table.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | 5 | angular 6 | 7 | .module('chartbuilderDirectives') 8 | 9 | .directive('liveDataTable', ['chartbuilderUtils', 'chartbuilderData', function(chartbuilderUtils, chartbuilderData) { 10 | return { 11 | restrict: 'EA', 12 | template: require('../../partials/data-forms/live-data-table.html'), 13 | controller: function($scope) { 14 | if (chartbuilderUtils.getType(chartbuilderData.dataFormat[0].values) === 'array') { 15 | //console.log(chartbuilderData.dataFormat); 16 | } else { 17 | $scope.data = chartbuilderData.data; 18 | } 19 | } 20 | }; 21 | }]) 22 | 23 | .directive('mapDataGroups', ['chartbuilderUtils', 'chartbuilderData', function(chartbuilderUtils, chartbuilderData) { 24 | return { 25 | restrict: 'EA', 26 | link: function($scope) { 27 | $scope.$watch('structureData.dataFormat', function(format) { 28 | console.log(format); 29 | if (chartbuilderUtils.getType(format[0].values) === 'array') { 30 | console.log('is array'); 31 | console.log(chartbuilderData.data); 32 | $scope.groups = chartbuilderData.data[0].values; 33 | } else { 34 | $scope.groups = chartbuilderData.data; 35 | } 36 | console.log($scope.groups); 37 | }); 38 | $scope.$watch('groups', function(newval) { 39 | console.log(newval); 40 | }, true); 41 | } 42 | }; 43 | }]); 44 | -------------------------------------------------------------------------------- /app/scripts/directives/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | 5 | .module('chartbuilderDirectives', [ 6 | 'fileInput', 7 | 'ui.sortable', 8 | 'slugifier', 9 | 'chartbuilderOptions' 10 | ]); 11 | -------------------------------------------------------------------------------- /app/scripts/directives/save-images.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./module'); 4 | 5 | require('RGBColor'); 6 | require('StackBlur'); 7 | var canvg = require('../../bower_components/canvg/canvg'); 8 | 9 | 10 | function copySvg(svgEl) { 11 | var copyEl = svgEl.cloneNode(true), 12 | defs = document.createElement('defs'); 13 | 14 | copyEl.insertBefore(defs, copyEl.firstChild); 15 | 16 | var appliedStyles = '', 17 | sheets = document.styleSheets; 18 | 19 | /* 20 | for (var i = 0; i < sheets.length; i++) { 21 | var rules = sheets[i].cssRules; 22 | for (var j = 0; j < rules.length; j++) { 23 | var rule = rules[j]; 24 | if ('undefined' !== typeof(rule.style)) { 25 | try { 26 | var elems = svgEl.querySelectorAll(rule.selectorText); 27 | if (elems.length > 0) { 28 | appliedStyles += rule.selectorText + ' { ' + rule.style.cssText + ' }\n'; 29 | } 30 | } catch(e) { 31 | continue; 32 | } 33 | } 34 | } 35 | } 36 | */ 37 | var appliedStyles = 'path.nv-line { fill:none; }'; 38 | 39 | var style = document.createElement('style'); 40 | var cdata = document.createTextNode(appliedStyles); 41 | style.setAttribute('type', 'text/css'); 42 | style.appendChild(cdata); 43 | defs.appendChild(style); 44 | 45 | return (new XMLSerializer()).serializeToString(copyEl); 46 | } 47 | 48 | angular 49 | 50 | .module('chartbuilderDirectives') 51 | 52 | .directive('chartbuilderSaveToPng', function() { 53 | return { 54 | restrict: 'EA', 55 | replace: true, 56 | template: 'As an image', 57 | link: function(scope) { 58 | scope.makeImage = function(){ 59 | // Set up elements and svg 60 | var chartElement = document.getElementById('chart'), 61 | svg = copySvg(chartElement.getElementsByTagName('svg')[0]), 62 | canvas = document.getElementById('canvas'); 63 | 64 | // svg size has to be explicitly set. we already have height 65 | canvas.setAttribute('width', chartElement.offsetWidth); 66 | 67 | // SVG -> Canvas 68 | canvg('canvas', svg, { renderCallback: 'scope.downloadImage' }); 69 | return canvas.toDataURL('image/png'); 70 | }; 71 | 72 | scope.saveImage = function() { 73 | // Canvas -> file 74 | var a = document.createElement('a'); 75 | a.download = 'image.png'; 76 | a.href = scope.makeImage(); 77 | document.body.appendChild(a); 78 | a.click(); 79 | }; 80 | } 81 | }; 82 | }) 83 | 84 | .directive('chartbuilderSaveToSvg', function() { 85 | return { 86 | restrict: 'EA', 87 | replace: true, 88 | template: '', 89 | link: function(scope) { 90 | scope.svgToString = function() { 91 | 92 | // Set up elements and svg 93 | var chartElement = document.getElementById('chart'), 94 | svg = chartElement.getElementsByTagName('svg')[0], 95 | svgXml = (new XMLSerializer()).serializeToString(svg); 96 | 97 | // Bind svg string to textarea 98 | scope.exportedSVG = svgXml; 99 | 100 | }; 101 | } 102 | }; 103 | }); 104 | -------------------------------------------------------------------------------- /app/scripts/directives/template-loader.js: -------------------------------------------------------------------------------- 1 | /*global alert */ 2 | 3 | 'use strict'; 4 | 5 | require('./module'); 6 | 7 | function isJson(data) { 8 | try { 9 | return angular.fromJson(data); 10 | } catch(e) { 11 | console.log('Not a valid JSON object'); 12 | return false; 13 | } 14 | } 15 | 16 | function parseDataForWP(data) { 17 | if (angular.isUndefined(data) || 18 | angular.isUndefined(data.options.chart) || 19 | angular.isUndefined(data.slug)) { 20 | alert('You must select a chart type and add data before sending to WordPress'); 21 | return false; 22 | } 23 | 24 | // validate chart data 25 | if (!isJson(data)) { 26 | return false; 27 | } 28 | 29 | // validate chart type 30 | if (!data.slug.length) { 31 | console.log('invalid chart type'); 32 | return false; 33 | } 34 | 35 | // encode meta fields to avoid double quote issues 36 | angular.forEach(data.meta, function(value, key) { 37 | data.meta[key] = encodeURIComponent(value); 38 | }); 39 | 40 | // Unset preloaded for loading 41 | delete data.preloaded; 42 | 43 | // return chart data 44 | return angular.toJson(data); 45 | } 46 | 47 | angular 48 | 49 | .module('chartbuilderDirectives') 50 | 51 | .directive('chartOptionsLoader', function() { 52 | return { 53 | restrict: 'EA', 54 | replace: true, 55 | template: '
Upload Chart file
', 56 | link: function(scope) { 57 | // Get the file from the file-input directive, make sure it's json 58 | scope.readTemplateFile = function(file) { 59 | var optionsObject = isJson(file); 60 | 61 | if (optionsObject) { 62 | scope.chartbuilderData.load(optionsObject); 63 | } 64 | 65 | }; 66 | } 67 | }; 68 | }) 69 | 70 | .directive('chartTemplateOptionsLoader', function() { 71 | return { 72 | restrict: 'EA', 73 | replace: true, 74 | template: '', 75 | link: function(scope) { 76 | // Get the file from the file-input directive, make sure it's json 77 | scope.readTemplateFile = function(file) { 78 | var optionsObject = isJson(file); 79 | 80 | if (optionsObject) { 81 | scope.chartbuilderData.loadOptions(optionsObject); 82 | } 83 | 84 | }; 85 | } 86 | }; 87 | }) 88 | 89 | .directive('chartOptionsSaver', ['chartbuilderUtils', function(chartbuilderUtils) { 90 | return { 91 | restrict: 'EA', 92 | template: 'As Chart file', 93 | link: function(scope, element, attrs) { 94 | // Download the current chartbuilderData object 95 | scope.downloadOptionsObject = function() { 96 | var optionsObject = scope.getOptions(); 97 | chartbuilderUtils.saveFile(optionsObject, 'chartbuilder-options.json', 'text/json'); 98 | }; 99 | 100 | scope.getOptions = function() { 101 | if (!attrs.optionsOnly) { 102 | delete scope.chartbuilderData.preloaded; 103 | return angular.toJson(scope.chartbuilderData); 104 | } else { 105 | var templateOptions = { 106 | colors: scope.chartbuilderData.colors, 107 | options: scope.chartbuilderData.options.chart 108 | }; 109 | 110 | return angular.toJson(templateOptions); 111 | } 112 | }; 113 | } 114 | }; 115 | }]) 116 | 117 | .directive('chartEmbedCode', ['chartbuilderData', 'chartbuilderDefaultOptions', function(chartbuilderData, chartbuilderDefaultOptions) { 118 | return { 119 | restrict: 'EA', 120 | replace: true, 121 | template: 'Create embed code', 122 | link: function(scope) { 123 | scope.makeEmbedCode = function() { 124 | if (!chartbuilderData.data[0].values.length) { 125 | return false; 126 | } 127 | var chartData = parseDataForWP(scope.chartbuilderData); 128 | var embedData = angular.fromJson(chartData); 129 | var templateString = embedData.template; 130 | delete embedData.template; 131 | 132 | var embedString = [ 133 | ''].join(''); 138 | 139 | chartbuilderData.embedCode = embedString; 140 | } 141 | } 142 | } 143 | }]) 144 | 145 | .directive('chartOptionsFromWindow', ['$window', 'chartbuilderData', 'chartbuilderDefaultOptions', function($window, chartbuilderData, chartbuilderDefaultOptions) { 146 | return { 147 | restrict: 'EA', 148 | replace: true, 149 | template: 'To WordPress', 150 | link: function(scope) { 151 | 152 | /** 153 | * WordPress plugin integration functions 154 | */ 155 | 156 | // this is initialized on the directive 157 | scope.initDataLoad = function() { 158 | 159 | if ( scope.isTopLevelWindow() ){ 160 | return; 161 | } 162 | 163 | // enable plugin specific tools 164 | chartbuilderData.env = 'iframe'; 165 | 166 | // setup postMessage listener and tell parent window that child frame is ready to receive data 167 | window.addEventListener('message', scope.receiveMessage, true); 168 | window.parent.postMessage( { 169 | src : 'chartbuilder', 170 | channel : 'upstream', 171 | msg : 'ready', 172 | data : null 173 | }, '*' ); 174 | // '*' is not ideal, but there are subsequent checks in parent window 175 | // and here to validate message origins 176 | 177 | }; 178 | 179 | // look iframe containing the app 180 | scope.isTopLevelWindow = function(){ 181 | try { 182 | // window.frameElement is null in top level window 183 | return window.frameElement === null; 184 | } catch ( err ){ 185 | // will throw SecurityError when attempting to access cross-origin iframe 186 | return err.name !== 'SecurityError'; 187 | } 188 | }; 189 | 190 | // allow postMessages from same-origin or *.wordpress.com 191 | // i.e. for VIP sites 192 | scope.matchOrigin = function( sender ){ 193 | var currentOrigin = $window.location.protocol + '//' + $window.location.hostname; 194 | 195 | // allow same origin, or any cross-origin message when developing with app hosted at http://chartbuidler.dev 196 | if ( sender === currentOrigin || 'http://chartbuilder.dev' === currentOrigin ){ 197 | //return true; 198 | } 199 | sender = 'http://kffpch.wp.alley.ws'; 200 | 201 | // test http and https on WPCOM subdomains 202 | var re = /^(https?):\/\/[a-z0-9\-\.]+(\.wordpress\.com|\.alley\.ws|\.pantheon\.io)/; 203 | console.log(sender); 204 | return re.test( sender ); 205 | }; 206 | 207 | scope.receiveMessage = function(e){ 208 | if ( ! scope.matchOrigin( e.origin ) ){ 209 | throw( 'Illegal postMessage from ' + e.origin ); 210 | } 211 | 212 | var msgObj = e.data; 213 | if ( !angular.isUndefined( msgObj.src) && 214 | msgObj.src === 'chartbuilder' && 215 | !angular.isUndefined( msgObj.channel ) && 216 | msgObj.channel === 'downstream' && 217 | !angular.isUndefined( msgObj.msg ) && 218 | (msgObj.msg === 'savedData' || msgObj.msg === 'options') && 219 | !angular.isUndefined( msgObj.data ) && 220 | msgObj.data 221 | ) { 222 | switch (msgObj.msg) { 223 | case 'savedData': 224 | console.log('App iframe received savedData from WordPress'); 225 | console.log(msgObj.data); 226 | chartbuilderData.load(msgObj.data); 227 | break; 228 | case 'options': 229 | console.log('App received options from WordPress'); 230 | console.log(msgObj.data); 231 | chartbuilderDefaultOptions.load(msgObj.data); 232 | break; 233 | } 234 | } 235 | }; 236 | 237 | scope.initDataLoad(); 238 | 239 | scope.sendToWordPress = function() { 240 | 241 | var chartData = parseDataForWP(scope.chartbuilderData); 242 | 243 | var chartImg = scope.makeImage(); 244 | 245 | $window.parent.postMessage({ 246 | src : 'chartbuilder', 247 | channel : 'upstream', 248 | msg : 'chartData', 249 | data : { 250 | chartData : chartData, 251 | chartImg : chartImg 252 | } 253 | }, '*'); 254 | }; 255 | } 256 | }; 257 | }]); 258 | -------------------------------------------------------------------------------- /app/scripts/filters/filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Filters */ 4 | var coerceInputTypes = { 5 | 'number': function(input) { 6 | var number = parseFloat(input.replace(/[^0-9-.]/g, '')); 7 | if (isNaN(number)) { 8 | return null; 9 | } else { 10 | return number; 11 | } 12 | }, 13 | 'text': function(input) { 14 | return input; 15 | } 16 | }; 17 | 18 | angular 19 | .module('chartbuilderFilters', []) 20 | 21 | .filter('numberFilter', function() { 22 | return function(input) { 23 | return input.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 24 | }; 25 | }) 26 | 27 | .filter('datatype', function() { 28 | return function(input, type) { 29 | return coerceInputTypes[type](input); 30 | }; 31 | }); 32 | -------------------------------------------------------------------------------- /app/scripts/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function() { 4 | require('jquery'); 5 | 6 | // Require angular 7 | var angular = require('../bower_components/angular/angular'); 8 | 9 | // Main app dependencies 10 | require('../bower_components/angular-resource/angular-resource'); 11 | require('../bower_components/angular-animate/angular-animate'); 12 | require('../bower_components/angular-ui-router/release/angular-ui-router'); 13 | require('../bower_components/angular-bootstrap/ui-bootstrap-tpls'); 14 | require('../bower_components/jquery-ui/jquery-ui'); 15 | require('../bower_components/sass-bootstrap/dist/js/bootstrap'); 16 | 17 | // Angular modules 18 | require('./controllers/controllers'); 19 | require('./directives/directives'); 20 | require('./filters/filters'); 21 | require('./services/services'); 22 | 23 | // NVd3 24 | require('./angular_modules/nvd3-modules/chartbuilderNvd3'); 25 | 26 | // Datamaps 27 | require('./angular_modules/datamaps/main'); 28 | 29 | // Highcharts 30 | require('./angular_modules/highcharts/main'); 31 | 32 | angular 33 | 34 | .module('angulard3Chartbuilder', [ 35 | 'ui.router', 36 | 'ngResource', 37 | 'ui.bootstrap', 38 | 'ngAnimate', 39 | 'chartbuilderControllers', 40 | 'chartbuilderFilters', 41 | 'chartbuilderServices', 42 | 'chartbuilderDirectives', 43 | 'chartbuilder.nvd3', 44 | 'chartbuilder.datamaps', 45 | 'chartbuilder.highcharts' 46 | ]) 47 | 48 | .config([ 49 | '$stateProvider', 50 | '$urlRouterProvider', 51 | '$locationProvider', 52 | function($stateProvider, $urlRouterProvider) { 53 | $stateProvider 54 | .state('/', { 55 | url: '/', 56 | template: require('../partials/home.html'), 57 | controller: 'Home' 58 | }) 59 | .state('chartbuilder', { 60 | url: '/chartbuilder', 61 | template: require('../partials/chartbuilder.html'), 62 | controller: 'Chartbuilder' 63 | }) 64 | .state('about', { 65 | url: '/about', 66 | template: require('../partials/about.html') 67 | }) 68 | .state('tutorials', { 69 | url: '/tutorials', 70 | template: require('../partials/tutorials.html'), 71 | controller: 'ChartbuilderTutorials' 72 | }) 73 | .state('faq', { 74 | url: '/faq', 75 | template: require('../partials/faq.html'), 76 | controller: 'ChartbuilderFAQ' 77 | }) 78 | .state('404', { 79 | url: '/404', 80 | template: require('../404.html') 81 | }); 82 | 83 | $urlRouterProvider.otherwise('/'); 84 | }]); 85 | 86 | angular.element(document).ready(function () { 87 | var $html = angular.element('html'); 88 | angular.bootstrap($html, ['angulard3Chartbuilder']); 89 | }); 90 | })(); 91 | -------------------------------------------------------------------------------- /app/styles/_animations.scss: -------------------------------------------------------------------------------- 1 | @import 'compass/css3/transition'; 2 | 3 | [ui-view] { 4 | width: 100%; 5 | } 6 | 7 | [ui-view].ng-enter { 8 | @include single-transition(all, 0.2s, ease); 9 | position: absolute; 10 | } 11 | 12 | [ui-view].ng-enter { 13 | opacity: 0; 14 | left: 100%; 15 | } 16 | 17 | [ui-view].ng-enter.ng-enter-active { 18 | opacity: 1; 19 | left: 0; 20 | } 21 | -------------------------------------------------------------------------------- /app/styles/_charts.scss: -------------------------------------------------------------------------------- 1 | #chart { 2 | position: relative; 3 | } 4 | #map-container { 5 | position: relative; 6 | } 7 | .panel-body.charts { 8 | min-height: 635px; 9 | } 10 | .chartbuilder-affixed { 11 | width: inherit; 12 | } 13 | -------------------------------------------------------------------------------- /app/styles/_color-picker.scss: -------------------------------------------------------------------------------- 1 | .color-picker { 2 | > span { 3 | float: left; 4 | height: 20px; 5 | width: 20px; 6 | display: block; 7 | margin: 0 3px 3px 0; 8 | cursor: pointer; 9 | &.color-box { 10 | border: 1px solid #b9b9b9; 11 | &:hover { 12 | border: 1px solid #ffffff; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/styles/_custom_mixins.scss: -------------------------------------------------------------------------------- 1 | $dark-grey: #333333; 2 | $grey: #424242; 3 | $aqua: #00ccd6; 4 | $off-white: #efefef; 5 | $yellow: #ffd900; 6 | 7 | $width-small: 400px; 8 | $width-medium: 760px; 9 | $width-large: 1200px; 10 | 11 | @mixin custom-responsive($width) { 12 | @if $width == wide-screens { 13 | @media only screen and (max-width: $width-large) { @content; } 14 | } 15 | @else if $width == medium-screens { 16 | @media only screen and (max-width: $width-medium) { @content; } 17 | } 18 | @else if $width == small-screens { 19 | @media only screen and (max-width: $width-small) { @content; } 20 | } 21 | } 22 | 23 | // @include responsive(wide-screens) { width: 80%; } 24 | 25 | @mixin custom-retinize($file, $type, $width, $height) { 26 | background-image: url('../img/' + $file + '.' + $type); 27 | 28 | @media (-webkit-min-device-pixel-ratio: 1.5), 29 | (min--moz-device-pixel-ratio: 1.5), 30 | (-o-min-device-pixel-ratio: 3/2), 31 | (min-device-pixel-ratio: 1.5), 32 | (min-resolution: 1.5dppx) { 33 | & { 34 | background-image: url('../img/' + $file + '-2x.' + $type); 35 | -webkit-background-size: $width $height; 36 | -moz-background-size: $width $height; 37 | background-size: $width $height; 38 | } 39 | } 40 | } 41 | 42 | // how to use @include retinize('icon-dribbble', 'png', 24px, 24px); 43 | 44 | @mixin custom-rounded($radius) { 45 | -webkit-border-radius: $radius; 46 | -moz-border-radius: $radius; 47 | border-radius: $radius; 48 | } 49 | @mixin custom-shadow($x, $y, $blur, $color) { 50 | -webkit-box-shadow: $x $y $blur $color; 51 | -moz-box-shadow: $x $y $blur $color; 52 | box-shadow: $x $y $blur $color; 53 | } 54 | @mixin custom-shadow-inset($x, $y, $blur, $color) { 55 | -webkit-box-shadow: inset $x $y $blur $color; 56 | -moz-box-shadow: inset $x $y $blur $color; 57 | box-shadow: inset $x $y $blur $color; 58 | } 59 | @mixin custom-transition($property) { 60 | -webkit-transition: $property .2s ease; 61 | -moz-transition: $property .2s ease; 62 | -o-transition: $property .2s ease; 63 | transition: $property .2s ease; 64 | } 65 | @mixin custom-box-sizing { 66 | -webkit-box-sizing: border-box; 67 | -moz-box-sizing: border-box; 68 | box-sizing: border-box; 69 | } 70 | @mixin custom-linear-gradient($from, $to) { 71 | /* Fallback for sad browsers */ 72 | background-color: $to; 73 | /* Mozilla Firefox */ 74 | background-image:-moz-linear-gradient($from, $to); 75 | /* Opera */ 76 | background-image:-o-linear-gradient($from, $to); 77 | /* WebKit (Chrome 11+) */ 78 | background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, $from), color-stop(1, $to)); 79 | /* WebKit (Safari 5.1+, Chrome 10+) */ 80 | background-image: -webkit-linear-gradient($from, $to); 81 | /* IE10 */ 82 | background-image: -ms-linear-gradient($from, $to); 83 | /* W3C */ 84 | background-image: linear-gradient($from, $to); 85 | } 86 | @mixin text-highlight-selection($background, $color) { 87 | ::selection { background: $background; color: $color; text-shadow: none; } 88 | ::-webkit-selection{ background: $background; color: $color; text-shadow: none; } 89 | ::-moz-selection{ background: $background; color: $color; text-shadow: none; } 90 | } 91 | -------------------------------------------------------------------------------- /app/styles/_editinplace.scss: -------------------------------------------------------------------------------- 1 | .edit-in-place { 2 | &.active { 3 | div { 4 | display: none; 5 | } 6 | textarea { 7 | display: inline-block; 8 | } 9 | } 10 | &.empty { 11 | div { 12 | min-height: 12px; 13 | border-left: 2px solid #b9b9b9; 14 | } 15 | } 16 | div { 17 | cursor: pointer; 18 | &.emptyData { 19 | min-height: 1.42em; 20 | } 21 | } 22 | textarea { 23 | display: none; 24 | } 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/styles/_home.scss: -------------------------------------------------------------------------------- 1 | .chartbuilder-home { 2 | img { 3 | width: 100%; 4 | } 5 | .jumbotron { 6 | height: 100%; 7 | .dropdown { 8 | display: inline-block; 9 | h2 { 10 | min-width: 300px; 11 | } 12 | .dropdown-menu { 13 | width: 100%; 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/styles/_navbar.scss: -------------------------------------------------------------------------------- 1 | .navbar-chartbuilder { 2 | background-color: #e7e7e7; 3 | border-color: #b9b9b9; 4 | .navbar-brand { 5 | background: url('../images/C.png') 15px 13px no-repeat; 6 | padding-left: 33px; 7 | color: #424242; 8 | } 9 | .navbar-nav { 10 | .active { 11 | a { 12 | background-color: #d9d9d9; 13 | &:hover { 14 | background-color: #d1d1d1; 15 | } 16 | } 17 | } 18 | li:hover { 19 | a { 20 | background-color: #d1d1d1; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/styles/_options.scss: -------------------------------------------------------------------------------- 1 | chartbuilder-options ul { 2 | background-color: #fff; 3 | padding: 0; 4 | list-style: none; 5 | li { 6 | cursor: pointer; 7 | padding: 5px 5px; 8 | line-height: 30px; 9 | border-bottom: 1px solid #f5f5f5; 10 | &:hover, &.active { 11 | border-left: 4px solid #3276b1; 12 | } 13 | } 14 | ul { 15 | margin: 0; 16 | padding: 10px 0 10px 15px; 17 | } 18 | } 19 | .panel-body.chartbuilder-panel-options { 20 | padding: 0; 21 | } 22 | -------------------------------------------------------------------------------- /app/styles/_sidebar.scss: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | .chartbuilder-sidebar-group { 3 | background: #f8f8f8; 4 | padding: 0 0 10px; 5 | @include box-shadow(1px 1px 1px #e7e7e7); 6 | h2.select-dropdown { 7 | cursor: pointer; 8 | &:hover { 9 | color: $grey; 10 | } 11 | } 12 | .btn-chartbuilder-group { 13 | margin: 0 0 10px; 14 | } 15 | .chart-dropdown { 16 | position: relative; 17 | margin: 20px 0; 18 | .btn-chart-picker { 19 | @include button-variant(#3276b1, #FFF, #3276b1); 20 | text-align: left; 21 | font-weight: bold; 22 | width: 100%; 23 | } 24 | } 25 | .well { 26 | margin-top: 0; 27 | } 28 | textarea.paste-input { 29 | min-height: 180px; 30 | font-family: monospace; 31 | } 32 | .save-chart-group { 33 | border-top: 2px solid #e7e7e7; 34 | padding: 20px 0 10px; 35 | margin: 20px 0 0; 36 | } 37 | .panel-chartbuilder-table { 38 | .panel-body { 39 | padding: 0; 40 | } 41 | } 42 | .data-group-title-heading { 43 | border-bottom: 1px solid #ddd; 44 | } 45 | } 46 | .input-group { 47 | width: 100%; 48 | margin: 5px 0; 49 | } 50 | .chartbuilder-options { 51 | .panel-heading { 52 | padding: 15px 15px 0; 53 | } 54 | #collapse-advanced-options { 55 | .panel-body { 56 | padding: 0; 57 | } 58 | } 59 | } 60 | .dropdown-menu { 61 | width: 100%; 62 | > li { 63 | position: relative; 64 | > a { 65 | .thumbnail { 66 | position: absolute; 67 | left: 100%; 68 | top: -10px; 69 | display: none; 70 | width: 350px; 71 | height: auto; 72 | margin-left: 5px; 73 | } 74 | &:hover .thumbnail { 75 | display: block; 76 | } 77 | } 78 | > .btn-file-input { 79 | padding: 3px 20px; 80 | font-weight: bold; 81 | &:hover, &:focus { 82 | background-color: #f5f5f5; 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/styles/style.scss: -------------------------------------------------------------------------------- 1 | $fa-font-path: '../bower_components/font-awesome/fonts'; 2 | @import '../bower_components/font-awesome/scss/font-awesome'; 3 | @import '../bower_components/animate-sass/animate'; 4 | $icon-font-path: '../bower_components/sass-bootstrap/fonts/'; 5 | @import '../bower_components/sass-bootstrap/lib/bootstrap'; 6 | @import 'navbar.scss'; 7 | @import 'custom_mixins.scss'; 8 | @import 'animations.scss'; 9 | @import 'home.scss'; 10 | @import 'charts.scss'; 11 | @import 'sidebar.scss'; 12 | @import 'options.scss'; 13 | @import 'editinplace.scss'; 14 | @import 'color-picker.scss'; 15 | @import 'spectrum'; 16 | 17 | /* This is your main css file */ 18 | .browsehappy { 19 | margin: 0.2em 0; 20 | background: #ccc; 21 | color: #000; 22 | padding: 0.2em 0; 23 | } 24 | /* Space out content a bit */ 25 | 26 | body { 27 | padding-bottom: 20px; 28 | > .main-content-container { 29 | margin: 50px 0 0; 30 | } 31 | /* Container relative to hold animated content */ 32 | .container { 33 | .main-content-container { 34 | position: relative; 35 | } 36 | } 37 | } 38 | 39 | /* Everything but the jumbotron gets side spacing for mobile first views */ 40 | 41 | .header, 42 | .marketing, 43 | .footer { 44 | padding-left: 15px; 45 | padding-right: 15px; 46 | } 47 | /* Custom page footer */ 48 | 49 | .footer { 50 | padding-top: 19px; 51 | color: #777; 52 | border-top: 1px solid #e5e5e5; 53 | } 54 | .container-narrow > hr { 55 | margin: 30px 0; 56 | } 57 | /* Main marketing message and sign up button */ 58 | 59 | .jumbotron { 60 | text-align: center; 61 | border-bottom: 1px solid #e5e5e5; 62 | } 63 | .jumbotron .btn { 64 | font-size: 21px; 65 | padding: 14px 24px; 66 | } 67 | /* Supporting marketing content */ 68 | 69 | .marketing { 70 | margin: 40px 0; 71 | } 72 | .marketing p + h4 { 73 | margin-top: 28px; 74 | } 75 | 76 | /* Responsive: Portrait tablets and up */ 77 | 78 | @media screen and (min-width: 768px) { 79 | /* Space out the masthead */ 80 | .header { 81 | margin-bottom: 30px; 82 | } 83 | /* Remove the bottom border on the jumbotron for visual effect */ 84 | .jumbotron { 85 | border-bottom: 0; 86 | } 87 | } 88 | @media screen and (min-width: 992px) { 89 | } 90 | 91 | @media screen and (min-width: 1200px) { 92 | } 93 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angulard3builder", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "sass-bootstrap": "*", 6 | "font-awesome": "*", 7 | "underscore": "*", 8 | "angular": "*", 9 | "angular-resource": "*", 10 | "angular-mocks": "*", 11 | "angular-bootstrap": "*", 12 | "angular-animate": "*", 13 | "jquery": "*", 14 | "jquery-ui": "*", 15 | "animate-sass": "*", 16 | "requirejs": "*", 17 | "modernizr": "*", 18 | "d3": "~3.4.3", 19 | "nvd3": "~1.1.15-beta", 20 | "datamaps": "~0.3.2", 21 | "angular-ui-router": "~0.2.11", 22 | "canvg": "https://canvg.googlecode.com/files/canvg-1.3.zip", 23 | "angular-file-input": "git@github.com:dmachat/angular-file-input.git", 24 | "angular-datamaps": "*", 25 | "highcharts": "git@github.com:highslide-software/highcharts-release", 26 | "highcharts-ng": "https://github.com/pablojim/highcharts-ng.git", 27 | "angular-spectrum-colorpicker": "git@github.com:Jimdo/angular-spectrum-colorpicker.git", 28 | "chartbuilder-widget": "git@github.com:dmachat/chartbuilder-widget.git", 29 | "d3-browserify": "https://github.com/zcbenz/d3-browserify.git#3.4.12", 30 | "slugifier": "https://github.com/paulsmith/angular-slugify.git" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /config/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | 3 | module.exports = function(config) { 4 | config.set({ 5 | 6 | // base path, that will be used to resolve files and exclude 7 | basePath: '..', 8 | 9 | 10 | // frameworks to use 11 | frameworks: ['jasmine', 'requirejs'], 12 | 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | {pattern: 'app/bower_components/**/*.js', included: false}, 17 | {pattern: 'app/scripts/**/*.js', included: false}, 18 | {pattern: 'test/**/*Spec.js', included: false}, 19 | 'test/test-main.js', 20 | ], 21 | 22 | 23 | // list of files to exclude 24 | exclude: [ 25 | 'scripts/main.js' 26 | ], 27 | 28 | 29 | // test results reporter to use 30 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 31 | reporters: ['progress'], 32 | 33 | 34 | // web server port 35 | port: 9876, 36 | 37 | 38 | // enable / disable colors in the output (reporters and logs) 39 | colors: true, 40 | 41 | 42 | // level of logging 43 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 44 | logLevel: config.LOG_INFO, 45 | 46 | 47 | // enable / disable watching file and executing tests whenever any file changes 48 | autoWatch: false, 49 | 50 | 51 | // Start these browsers, currently available: 52 | // - Chrome 53 | // - ChromeCanary 54 | // - Firefox 55 | // - Opera (has to be installed with `npm install karma-opera-launcher`) 56 | // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) 57 | // - PhantomJS 58 | // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) 59 | browsers: ['PhantomJS'], 60 | 61 | 62 | // If browser does not capture in given timeout [ms], kill it 63 | captureTimeout: 60000, 64 | 65 | 66 | // Continuous Integration mode 67 | // if true, it capture browsers, run tests and exit 68 | singleRun: true 69 | }); 70 | }; 71 | -------------------------------------------------------------------------------- /config/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'), 2 | webpack = require('webpack'), 3 | 4 | appRoot = path.join(__dirname, '../app'), 5 | bowerRoot = path.join(__dirname, '../app/bower_components'), 6 | modulesRoot = path.join(__dirname, '../app/scripts/angular_modules'); 7 | 8 | module.exports = { 9 | cache: true, 10 | 11 | entry: path.join(appRoot, 'scripts/main.js'), 12 | 13 | output: { 14 | path: path.join(__dirname, '../dist/scripts'), 15 | filename: 'main.bundle.js', 16 | chunkFilename: '[id].main.bundle.js', 17 | sourceMapFilename: '[id].main.bundle.map' 18 | }, 19 | 20 | resolve: { 21 | root: bowerRoot, 22 | 23 | alias: { 24 | 'jquery': path.join(bowerRoot, 'jquery/dist/jquery'), 25 | 'd3': path.join(bowerRoot, 'd3-browserify/d3'), 26 | 'topojson': path.join(bowerRoot, 'topojson/topojson'), 27 | 'datamaps': path.join(bowerRoot, 'datamaps/dist/datamaps.all'), 28 | 'nvd3': path.join(bowerRoot, 'nvd3/nv.d3'), 29 | 'RGBColor': path.join(bowerRoot, 'canvg/rgbcolor'), 30 | 'StackBlur': path.join(bowerRoot, 'canvg/StackBlur') 31 | }, 32 | }, 33 | 34 | plugins: [], 35 | 36 | resolveLoader: { 37 | root: [ 38 | path.join(__dirname, 'node_modules') 39 | ] 40 | }, 41 | 42 | module: { 43 | noParse: [ bowerRoot ], 44 | preLoaders: [ 45 | { 46 | test: /\.js$/, 47 | loader: 'source-map-loader' 48 | } 49 | ], 50 | loaders: [ 51 | { 52 | test: /[\/]angular(\.min)?\.js$/, 53 | loader: 'exports?angular' 54 | }, 55 | { 56 | test: /[\/]jquery(\.min)?\.js$/, 57 | loader: 'expose?jQuery' 58 | }, 59 | { 60 | test: /[\/]datamaps(\.\w)?(\.min)?\.js$/, 61 | loader: 'exports?Datamap' 62 | }, 63 | { 64 | test: /[\/]rgbcolor(\.min)?\.js$/, 65 | loader: 'exports?RGBColor' 66 | }, 67 | { 68 | test: /[\/]StackBlur(\.min)?\.js$/, 69 | loader: 'exports?stackBlurCanvasRGBA' 70 | }, 71 | { 72 | test: /[\/]canvg(\.min)?\.js$/, 73 | loader: 'exports?canvg!imports?RGBColor,StackBlur' 74 | }, 75 | { 76 | test: /[\/]nv\.d3(\.min)?\.js$/, 77 | loader: 'imports?d3!exports?nv' 78 | }, 79 | { 80 | test: /[\/]datamaps(\.\w)?(\.min)?\.js$/, 81 | loader: 'imports?d3,topojson' 82 | }, 83 | { 84 | test: /[\/]angular-datamaps(\.min)?\.js$/, 85 | loader: 'imports?Datamap=datamaps' 86 | }, 87 | { 88 | test: /[\/]bootstrap(\.min)?\.js$/, 89 | loader: 'imports?jQuery=jquery' 90 | }, 91 | { 92 | test: /[\/]spectrum(\.min)?\.js$/, 93 | loader: 'imports?jQuery=jquery' 94 | }, 95 | { 96 | test: /[\/]angular-nvd3(\.min)?\.js$/, 97 | loader: 'imports?nv=nvd3,d3' 98 | }, 99 | { 100 | test: /\.html$/, 101 | loader: 'html' 102 | }, 103 | { 104 | test: /\.png$/, 105 | loader: 'url' 106 | } 107 | ] 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /dist/images/C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/C.png -------------------------------------------------------------------------------- /dist/images/cumulativeLineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/cumulativeLineChart.png -------------------------------------------------------------------------------- /dist/images/discreteBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/discreteBarChart.png -------------------------------------------------------------------------------- /dist/images/donutChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/donutChart.png -------------------------------------------------------------------------------- /dist/images/highcharts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/highcharts.png -------------------------------------------------------------------------------- /dist/images/historicalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/historicalBarChart.png -------------------------------------------------------------------------------- /dist/images/lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/lineChart.png -------------------------------------------------------------------------------- /dist/images/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/map.png -------------------------------------------------------------------------------- /dist/images/multiBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/multiBarChart.png -------------------------------------------------------------------------------- /dist/images/multiBarHorizontalChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/multiBarHorizontalChart.png -------------------------------------------------------------------------------- /dist/images/pieChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/pieChart.png -------------------------------------------------------------------------------- /dist/images/scatterChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/scatterChart.png -------------------------------------------------------------------------------- /dist/images/stackedAreaChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/stackedAreaChart.png -------------------------------------------------------------------------------- /dist/images/tutorial1-requirement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmachat/angularjs-d3-chartbuilder/1f830828117ea61b0236ad2c2e09e13bc23e5ac4/dist/images/tutorial1-requirement.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | chartbuilder 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 33 |
34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /dist/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /dist/scripts/chartbuilder-ui.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('chartbuilderOptions', []); 4 | 5 | 'use strict'; 6 | 7 | var d3 = require('d3'); 8 | 9 | // Normalize dates 10 | function normalizedDate(date) { 11 | var d = new Date(Date.parse(date)); 12 | return new Date(d.getTime() + d.getTimezoneOffset() * 60000); 13 | } 14 | 15 | var xKeyValue = { 16 | 'label': 'Key', 17 | 'option': function(d) { 18 | return d.key; 19 | } 20 | } 21 | 22 | var xLabelValue = { 23 | 'label': 'Label', 24 | 'option': function(d) { 25 | return d.label; 26 | } 27 | } 28 | 29 | var xValue = { 30 | 'label': 'X', 31 | 'option': function(d) { 32 | return d.x; 33 | } 34 | } 35 | 36 | var yValue = { 37 | 'label': 'Y', 38 | 'option': function(d) { 39 | return d.y; 40 | } 41 | } 42 | 43 | var yPercent = { 44 | 'label': 'Y Percent Value', 45 | 'option': function(d) { 46 | return d.y / 100; 47 | } 48 | } 49 | 50 | var yLabelValue = { 51 | 'label': 'Value', 52 | 'option': function(d) { 53 | return d.value; 54 | } 55 | } 56 | 57 | var formatters = { 58 | 'function:text': { 59 | 'label': 'Text (unformatted)', 60 | 'option': function(d) { 61 | return d; 62 | } 63 | }, 64 | 'function:percent': { 65 | 'label': 'Percent (no decimal)', 66 | 'option': function(d) { 67 | return d3.format('.0%')(d); 68 | } 69 | }, 70 | 'function:percent-.1': { 71 | 'label': 'Percent (0.1%)', 72 | 'option': function(d) { 73 | return d3.format('.1%')(d); 74 | } 75 | }, 76 | 'function:percent-.01': { 77 | 'label': 'Percent (0.01%)', 78 | 'option': function(d) { 79 | return d3.format('.2%')(d); 80 | } 81 | }, 82 | 'function:percent-unmultiplied': { 83 | 'label': 'Percent (unmultiplied)', 84 | 'option': function(d) { 85 | return d3.format('.0%')(d / 100); 86 | } 87 | }, 88 | 'function:price': { 89 | 'label': 'Currency (no decimal)', 90 | 'option': function(d) { 91 | return d3.format('$,.0f')(d); 92 | } 93 | }, 94 | 'function:price-.1': { 95 | 'label': 'Currency ($0.1)', 96 | 'option': function(d) { 97 | return d3.format('$,.1f')(d); 98 | } 99 | }, 100 | 'function:price-.01': { 101 | 'label': 'Currency ($.01)', 102 | 'option': function(d) { 103 | return d3.format('$,.2f')(d); 104 | } 105 | }, 106 | 'function:year': { 107 | 'label': 'Year (\'YY)', 108 | 'option': function(d) { 109 | return d3.time.format('\'%y')(new Date(d)); 110 | } 111 | }, 112 | 'function:year-yyyy': { 113 | 'label': 'Year (YYYY)', 114 | 'option': function(d) { 115 | return d3.time.format('%Y')(new Date(d)); 116 | } 117 | } 118 | } 119 | 120 | angular 121 | 122 | .module('chartbuilderOptions') 123 | 124 | .value('chartbuilderOptionHelp', { 125 | 'forceX': { 126 | 'help': 'Set the min (0) and the max (1) values to scale this axis to', 127 | 'label': 'x-Axis Endpoints' 128 | }, 129 | 'forceY': { 130 | 'help': 'Set the min (0) and the max (1) values to scale this axis to', 131 | 'label': 'y-Axis Endpoints' 132 | }, 133 | 'x': { 134 | 'help': 'Select the correct data type for values on this axis', 135 | 'label': 'x-Axis Datatype' 136 | }, 137 | 'y': { 138 | 'help': 'Select the correct data type for values on this axis', 139 | 'label': 'y-Axis Datatype' 140 | }, 141 | 'showXAxis': { 142 | 'label': 'Show x-Axis' 143 | }, 144 | 'showYAxis': { 145 | 'label': 'Show y-Axis' 146 | }, 147 | 'staggerLabels': { 148 | 'label': 'Stagger Tick Labels' 149 | }, 150 | 'rightAlignYAxis': { 151 | 'label': 'Align y-Axis to the right' 152 | }, 153 | 'tooltips': { 154 | 'label': 'Show Tooltips' 155 | }, 156 | 'tickFormat': { 157 | 'label': 'Tick Formatter' 158 | }, 159 | 'valueFormat': { 160 | 'label': 'Value Formatter' 161 | }, 162 | 'margin': { 163 | 'help': 'Adjust the whitespace around this element', 164 | 'label': 'Margin' 165 | } 166 | }) 167 | 168 | .value('chartbuilderOptionValues', { 169 | 170 | // 171 | // NVD3 options 172 | // 173 | 174 | 'interpolate': { 175 | 'linear': { 176 | 'label': 'linear' 177 | }, 178 | 'linear-closed': { 179 | 'label': 'linear-closed' 180 | }, 181 | 'step-before': { 182 | 'label': 'step-before' 183 | }, 184 | 'step-after': { 185 | 'label': 'step-after' 186 | }, 187 | 'basis': { 188 | 'label': 'basis' 189 | }, 190 | 'basis-open': { 191 | 'label': 'basis-open' 192 | }, 193 | 'basis-closed': { 194 | 'label': 'basis-closed' 195 | }, 196 | 'bundle': { 197 | 'label': 'bundle' 198 | }, 199 | 'cardinal': { 200 | 'label': 'bundle' 201 | }, 202 | 'cardinal-open': { 203 | 'label': 'cardinal-open' 204 | }, 205 | 'cardinal-closed': { 206 | 'label': 'cardinal-closed' 207 | }, 208 | 'monotone': { 209 | 'label': 'monotone' 210 | } 211 | }, 212 | 'style': { 213 | 'stack': { 214 | 'label': 'stack' 215 | }, 216 | 'stream': { 217 | 'label': 'stream' 218 | }, 219 | 'stream-center': { 220 | 'label': 'stream-center' 221 | }, 222 | 'expand': { 223 | 'label': 'expand' 224 | }, 225 | 'stack_percent': { 226 | 'label': 'stack_percent' 227 | } 228 | }, 229 | 'labelType': { 230 | 'key': { 231 | 'label': 'key' 232 | }, 233 | 'value': { 234 | 'label': 'value' 235 | }, 236 | 'percent': { 237 | 'label': 'percent' 238 | } 239 | }, 240 | 'valueFormat': formatters, 241 | 'tickFormat': formatters, 242 | 'x': { 243 | 'function:key/value': xKeyValue, 244 | 'function:x/y': xValue, 245 | 'function:label/value': xLabelValue, 246 | 'function:timestamp': { 247 | 'label': 'Timestamp', 248 | 'option': function(d) { 249 | if (isNaN(d.x)) { 250 | return null; 251 | } 252 | return new Date(+d.x); 253 | } 254 | }, 255 | 'function:date': { 256 | 'label': 'Date', 257 | 'option': function(d) { 258 | return normalizedDate(d.x); 259 | } 260 | }, 261 | 'function:datefromarray': { 262 | 'label': 'Date (Stacked Area)', 263 | 'option': function(d) { 264 | return normalizedDate(d[0]); 265 | } 266 | } 267 | }, 268 | 'y': { 269 | 'function:key/y': yValue, 270 | 'function:yPercentData': yPercent, 271 | 'function:label/value': yLabelValue, 272 | 'function:valuefromarray': { 273 | 'label': 'Value (Stacked Area)', 274 | 'option': function(d) { 275 | return d[1]; 276 | } 277 | } 278 | }, 279 | 'tooltipContent': { 280 | 'function:key/value': { 281 | 'label': 'key/value', 282 | 'option': function(key, y, e, graph) { 283 | return '

' + key + '

' +'

' + y + '

' ; 284 | } 285 | }, 286 | 'function:value only': { 287 | 'label': 'value only', 288 | 'option': function(key, y) { 289 | return '

' + y + '

'; 290 | } 291 | }, 292 | 'function:key only': { 293 | 'label': 'key only', 294 | 'option': function(key) { 295 | return '

' + key + '

'; 296 | } 297 | }, 298 | 'Default': { 299 | 'label': 'Default', 300 | 'option': null 301 | } 302 | }, 303 | 'tooltip': { 304 | 'function:multiBarChart': { 305 | 'label': 'multiBarChart', 306 | 'option': function(key, x, y) { 307 | return '

' + key + '

' + 308 | '

' + y + ' ' + x + '

'; 309 | } 310 | }, 311 | 'Default': { 312 | 'label': 'Default', 313 | 'option': null 314 | } 315 | }, 316 | 'fillQuartiles': { 317 | 'function:flat': { 318 | 'label': 'flat', 319 | 'option': function(d) { 320 | return d/4; 321 | } 322 | } 323 | }, 324 | 325 | // 326 | // Datamaps options 327 | // 328 | 'mapType': { 329 | 'usa': { 330 | 'label': 'usa' 331 | }, 332 | 'world': { 333 | 'label': 'world' 334 | } 335 | } 336 | }); 337 | 338 | 'use strict'; 339 | 340 | /** 341 | * @ngdoc module 342 | * @name chartbuilderCharts 343 | * @description chartbuilderCharts: Render chartbuilder charts in templates 344 | * @example 345 | 346 | 347 | 353 |
354 |
355 |
356 | */ 357 | 358 | angular 359 | 360 | .module('chartbuilderCharts', ['datamaps', 'chartbuilder.nvd3', 'chartbuilderOptions']) 361 | 362 | .value('pageCharts', {}) 363 | 364 | .directive('chartbuilderChart', ['$compile', function($compile) { 365 | return { 366 | restrict: 'EA', 367 | scope: { 368 | data: '=?' 369 | }, 370 | 371 | link: function(scope, element) { 372 | scope.dataStore = scope.data; 373 | 374 | // Define child scope and template 375 | var childScope = scope.$new(); 376 | 377 | // Define build template function 378 | scope.build = function(_scope) { 379 | var template = [ 380 | '

{{ data.meta.title }}

', 381 | '

{{ data.meta.subtitle }}

', 382 | scope.data.template, 383 | '

{{ data.meta.caption }}

', 384 | '
{{ data.meta.attribution }}
' 385 | ].join(''); 386 | element.html('').append($compile(template)(_scope)); 387 | }; 388 | 389 | // Refresh directive when data changes 390 | scope.$watch('data', function(data) { 391 | if (angular.isUndefined(data) || angular.isUndefined(data.template)) { 392 | return false; 393 | } 394 | childScope.$destroy(); 395 | childScope = scope.$new(); 396 | scope.build(childScope); 397 | }, true); 398 | 399 | // Build template view 400 | //scope.build(childScope); 401 | } 402 | }; 403 | }]) 404 | 405 | .controller('chartbuilderUICtrl', ['$scope', 'pageCharts', function($scope, pageCharts) { 406 | $scope.pageCharts = pageCharts; 407 | }]); 408 | 409 | angular.element(document).ready(function() { 410 | angular.bootstrap(document, ['chartbuilderCharts']); 411 | }); 412 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chartbuilder", 3 | "version": "0.0.1", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "grunt": "*", 7 | "grunt-contrib-copy": "*", 8 | "grunt-contrib-concat": "*", 9 | "grunt-contrib-uglify": "*", 10 | "grunt-contrib-compass": "*", 11 | "grunt-contrib-jshint": "*", 12 | "grunt-contrib-cssmin": "*", 13 | "grunt-contrib-connect": "*", 14 | "grunt-contrib-clean": "*", 15 | "grunt-contrib-htmlmin": "*", 16 | "grunt-build-control": "*", 17 | "karma-script-launcher": "*", 18 | "karma-chrome-launcher": "*", 19 | "karma-firefox-launcher": "*", 20 | "karma-jasmine": "*", 21 | "karma-phantomjs-launcher": "*", 22 | "karma": "*", 23 | "grunt-karma": "*", 24 | "grunt-contrib-jasmine": "*", 25 | "grunt-contrib-imagemin": "*", 26 | "grunt-contrib-watch": "*", 27 | "grunt-rev": "*", 28 | "grunt-shell": "*", 29 | "grunt-autoprefixer": "*", 30 | "grunt-usemin": "*", 31 | "grunt-modernizr": "*", 32 | "grunt-newer": "*", 33 | "grunt-svgmin": "*", 34 | "grunt-concurrent": "*", 35 | "time-grunt": "*", 36 | "jshint-stylish": "*", 37 | "grunt-jsbeautifier": "^0.2.6", 38 | "load-grunt-config": "~0.16.0", 39 | "webpack": "~1.4.15", 40 | "webpack-dev-server": "~1.7.0", 41 | "grunt-webpack": "~1.0.8", 42 | "exports-loader": "~0.6.2", 43 | "imports-loader": "~0.6.3", 44 | "html-loader": "~0.2.3", 45 | "ngtemplate-loader": "~0.1.3", 46 | "url-loader": "~0.5.5", 47 | "expose-loader": "~0.6.0", 48 | "source-map-loader": "~0.1.3" 49 | }, 50 | "engines": { 51 | "node": ">=0.8.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tasks/aliases.json: -------------------------------------------------------------------------------- 1 | { 2 | "serve": [ 3 | "clean:server", 4 | "concurrent:server", 5 | "concat", 6 | "autoprefixer", 7 | "copy:appcss", 8 | "connect:livereload", 9 | "watch" 10 | ], 11 | "build": [ 12 | "clean:dist", 13 | "copy", 14 | "webpack", 15 | "concat:ui" 16 | ], 17 | "push": [ 18 | "build", 19 | "buildcontrol:pages" 20 | ], 21 | "default": [ 22 | "newer:jshint", 23 | "build" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tasks/autoprefixer.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "browsers": ["last 1 version"] 4 | }, 5 | "dist": { 6 | "files": [{ 7 | "expand": true, 8 | "cwd": ".tmp/styles/", 9 | "src": "{,*/}*.", 10 | "app": { 11 | "html": "<%= yeoman.app %>/index.html", 12 | "ignorePath": "/" 13 | }, 14 | "dest": ".tmp/styles/" 15 | }] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tasks/buildcontrol.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "dir": "dist", 4 | "commit": true, 5 | "push": true, 6 | "message": "Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%" 7 | }, 8 | "pages": { 9 | "options": { 10 | "remote": "git@github.com:dmachat/angularjs-d3-chartbuilder.git", 11 | "branch": "gh-pages" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tasks/clean.json: -------------------------------------------------------------------------------- 1 | { 2 | "dist": { 3 | "files": [{ 4 | "dot": true, 5 | "src": [ 6 | ".tmp", 7 | "<%= yeoman.dist %>/*", 8 | "!<%= yeoman.dist %>/.git*", 9 | "!<%= yeoman.dist %>/index.html" 10 | ] 11 | }] 12 | }, 13 | "afterBuild": { 14 | "files": [{ 15 | "dot": true, 16 | "src": [ 17 | "<%= yeoman.dist %>/scripts/*.js", 18 | "!<%= yeoman.dist %>/chartbuilder.vendor.js", 19 | "!<%= yeoman.dist %>/scripts/main.js" 20 | ] 21 | }] 22 | }, 23 | "server": ".tmp" 24 | } 25 | -------------------------------------------------------------------------------- /tasks/compass.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "sassDir": "<%= yeoman.app %>/styles", 4 | "cssDir": ".tmp/styles", 5 | "generatedImagesDir": ".tmp/images/generated", 6 | "imagesDir": "<%= yeoman.app %>/images", 7 | "javascriptsDir": "/scripts", 8 | "fontsDir": "<%= yeoman.app %>/styles/fonts", 9 | "importPath": "<%= yeoman.app %>/bower_components", 10 | "httpImagesPath": "/images", 11 | "httpGeneratedImagesPath": "/images/generated", 12 | "httpFontsPath": "/styles/fonts", 13 | "relativeAssets": true, 14 | "assetCacheBuster": false 15 | }, 16 | "dist": { 17 | "options": { 18 | "generatedImagesDir": "<%= yeoman.dist %>/images/generated" 19 | } 20 | }, 21 | "server": { 22 | "options": { 23 | "debugInfo": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tasks/concat.json: -------------------------------------------------------------------------------- 1 | { 2 | "ui": { 3 | "src": [ 4 | "<%= yeoman.ui %>/_chartbuilder-options.js", 5 | "<%= yeoman.app %>/scripts/angular_modules/chartbuilder-options/options-constants.js", 6 | "<%= yeoman.ui %>/chart.js" 7 | ], 8 | "dest": "<%= yeoman.dist %>/scripts/chartbuilder-ui.js" 9 | }, 10 | "dev": { 11 | "src": [".tmp/styles/{,*/}*.css"], 12 | "dest": ".tmp/styles/style.css" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tasks/concurrent.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": [ 3 | "compass:server" 4 | ], 5 | "dist": [ 6 | "compass", 7 | "copy:styles", 8 | "imagemin", 9 | "svgmin" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tasks/connect.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "port": 9000, 4 | "livereload": 35729, 5 | "hostname": "chartbuilder.dev" 6 | }, 7 | "livereload": { 8 | "options": { 9 | "open": true, 10 | "base": [ 11 | ".tmp", 12 | "<%= yeoman.app %>" 13 | ] 14 | } 15 | }, 16 | "dist": { 17 | "options": { 18 | "open": true, 19 | "base": "<%= yeoman.dist %>", 20 | "livereload": false 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tasks/copy.json: -------------------------------------------------------------------------------- 1 | { 2 | "dist": { 3 | "files": [{ 4 | "expand": true, 5 | "dot": true, 6 | "cwd": "<%= yeoman.app %>", 7 | "dest": "<%= yeoman.dist %>", 8 | "src": [ 9 | "*.{ico,png,txt}", 10 | "styles/fonts/{,*/}*.*", 11 | "styles/style.css", 12 | "images/*", 13 | "bower_components/sass-bootstrap/fonts/*.*", 14 | "bower_components/font-awesome/fonts/*.*", 15 | "bower_components/nvd3/*.css", 16 | "bower_components/spectrum/*.css", 17 | "bower_components/angular-file-input/dist/*.css", 18 | "bower_components/chartbuilder-widget/dist/release/js/*.js", 19 | "bower_components/chartbuilder-widget/loader/dist/*.js" 20 | ] 21 | }] 22 | }, 23 | "appcss": { 24 | "files": [{ 25 | "expand": true, 26 | "dot": true, 27 | "cwd": ".tmp/styles", 28 | "dest": "<%= yeoman.app %>/styles", 29 | "src": "{,*/}*.css" 30 | }] 31 | }, 32 | "styles": { 33 | "expand": true, 34 | "dot": true, 35 | "cwd": "<%= yeoman.app %>/styles", 36 | "dest": ".tmp/styles/", 37 | "src": "{,*/}*.css" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tasks/htmlmin.json: -------------------------------------------------------------------------------- 1 | { 2 | "dist": { 3 | "options": { 4 | "collapseBooleanAttributes": true, 5 | "collapseWhitespace": true, 6 | "removeAttributeQuotes": true, 7 | "removeCommentsFromCDATA": true, 8 | "removeEmptyAttributes": true, 9 | "removeOptionalTags": true, 10 | "removeRedundantAttributes": true, 11 | "useShortDoctype": true 12 | }, 13 | "files": [{ 14 | "expand": true, 15 | "cwd": "<%= yeoman.dist %>", 16 | "src": "{,*/}*.html", 17 | "dest": "<%= yeoman.dist %>" 18 | }] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tasks/imagemin.json: -------------------------------------------------------------------------------- 1 | { 2 | "dist": { 3 | "files": [{ 4 | "expand": true, 5 | "cwd": "<%= yeoman.app %>/images", 6 | "src": "{,*/}*.{gif,jpeg,jpg,png}", 7 | "dest": "<%= yeoman.dist %>/images" 8 | }] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tasks/jshint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | jshint: { 3 | options: { 4 | jshintrc: '.jshintrc', 5 | reporter: require('jshint-stylish'), 6 | }, 7 | all: [ 8 | 'Gruntfile.js', 9 | '<%= yeoman.app %>/scripts/{,*/}*.js', 10 | '!<%= yeoman.app %>/scripts/vendor/*', 11 | '<%= yeoman.ui %>/*.js', 12 | 'test/spec/{,*/}*.js' 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tasks/svgmin.json: -------------------------------------------------------------------------------- 1 | { 2 | "dist": { 3 | "files": [{ 4 | "expand": true, 5 | "cwd": "<%= yeoman.app %>/images", 6 | "src": "{,*/}*.svg", 7 | "dest": "<%= yeoman.dist %>/images" 8 | }] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tasks/usemin.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "assetsDirs": ["<%= yeoman.dist %>"] 4 | }, 5 | "html": ["<%= yeoman.dist %>/{,*/}*.html"], 6 | "css": ["<%= yeoman.dist %>/styles/{,*/}*.css"] 7 | } 8 | -------------------------------------------------------------------------------- /tasks/useminPrepare.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "dest": "<%= yeoman.dist %>" 4 | }, 5 | "html": "<%= yeoman.app %>/index.html" 6 | } 7 | -------------------------------------------------------------------------------- /tasks/watch.json: -------------------------------------------------------------------------------- 1 | { 2 | "js": { 3 | "files": [ 4 | "<%= yeoman.app %>/scripts/{,*/}*.js", 5 | "<%= yeoman.ui %>/*.js" 6 | ], 7 | "tasks": ["webpack:dev"] 8 | }, 9 | "jstest": { 10 | "files": ["test/spec/{,*/}*.js"], 11 | "tasks": ["test:watch"] 12 | }, 13 | "gruntfile": { 14 | "files": ["Gruntfile.js"] 15 | }, 16 | "compass": { 17 | "files": ["<%= yeoman.app %>/styles/{,*/}*.{scss,sass}"], 18 | "tasks": ["compass:server", "autoprefixer"] 19 | }, 20 | "livereload": { 21 | "options": { 22 | "livereload": "<%= connect.options.livereload %>" 23 | }, 24 | "files": [ 25 | "<%= yeoman.app %>/{,*/}*.html", 26 | ".tmp/styles/{,*/}*.css", 27 | "<%= yeoman.app %>/images/{,*/}*.{gif,jpeg,jpg,png,svg,webp}" 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tasks/webpack.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | var webpack = require('webpack'), 3 | webpackConfig = require('../config/webpack.config.js'); 4 | 5 | return { 6 | options: webpackConfig, 7 | prod: { 8 | plugins: webpackConfig.plugins.concat( 9 | new webpack.optimize.UglifyJsPlugin({ 10 | minimize: true, 11 | mangle: false, 12 | preserveComments: false 13 | }) 14 | ), 15 | output: { 16 | filename: 'main.bundle.min.js', 17 | chunkFilename: '[id].main.bundle.min.js' 18 | } 19 | }, 20 | dev: { 21 | debug: true 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tasks/yeoman.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "app", 3 | "ui": "ui", 4 | "dist": "dist" 5 | } 6 | -------------------------------------------------------------------------------- /test/specs/angularInjectionSpec.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'loadingSpec' 3 | ], function() { 4 | describe('angular template testing', function() { 5 | var element; 6 | var $scope; 7 | beforeEach(module('webApp')); 8 | beforeEach(inject( function($compile, _$rootScope_) { 9 | $scope = _$rootScope_; 10 | element = angular.element("
[[2 + 2]]
"); 11 | element = $compile(element)($scope); 12 | } )); 13 | 14 | it('should do something useful', function() { 15 | $scope.$digest(); 16 | expect(element.html()).toBe("4"); 17 | }); 18 | 19 | it('should do something more useful', function() { 20 | expect(element.hasClass("plain")).toBe(true); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/specs/loadingSpec.js: -------------------------------------------------------------------------------- 1 | define('loadingSpec', [ 2 | 'angular', 3 | 'angular-route', 4 | 'angular-resource', 5 | 'angular-mocks', 6 | 'controllers', 7 | 'services', 8 | 'filters', 9 | 'directives' 10 | ], function(angular) { 11 | angular.module('webApp', [ 12 | 'ngRoute', 13 | 'ngResource', 14 | 'webControllers', 15 | 'webFilters', 16 | 'webServices', 17 | 'webDirectives' 18 | ]).config(['$interpolateProvider', 19 | function($interpolateProvider) { 20 | /* change configure to use [[ to be the interpolation */ 21 | $interpolateProvider.startSymbol('[['); 22 | $interpolateProvider.endSymbol(']]'); 23 | } 24 | ]); 25 | }); 26 | -------------------------------------------------------------------------------- /test/test-main.js: -------------------------------------------------------------------------------- 1 | var tests = []; 2 | for (var file in window.__karma__.files) { 3 | if (window.__karma__.files.hasOwnProperty(file)) { 4 | if (/Spec\.js$/.test(file)) { 5 | tests.push(file); 6 | } 7 | } 8 | } 9 | requirejs.config({ 10 | // Karma serves files from '/app' 11 | baseUrl: 'base/app/scripts', 12 | paths: { 13 | 'angular': '../bower_components/angular/angular', 14 | 'angular-resource': '../bower_components/angular-resource/angular-resource', 15 | 'angular-route': '../bower_components/angular-route/angular-route', 16 | 'angular-mocks': '../bower_components/angular-mocks/angular-mocks', 17 | 'controllers': 'controllers/controllers', 18 | 'directives': 'directives/directives', 19 | 'filters': 'filters/filters', 20 | 'services': 'services/services' 21 | }, 22 | shim: { 23 | 'angular': { 24 | exports: 'angular' 25 | }, 26 | 'angular-resource': ['angular'], 27 | 'angular-route': ['angular'], 28 | 'angular-mocks': ['angular'], 29 | 'bootstrap': ['jquery'], 30 | 'controllers': ['angular', 'services'], 31 | 'filters': ['angular'], 32 | 'services': ['angular'], 33 | 'directives': ['angular'] 34 | }, 35 | // ask Require.js to load these files (all our tests) 36 | deps: tests, 37 | 38 | // start test run, once Require.js is done 39 | callback: window.__karma__.start 40 | }); 41 | -------------------------------------------------------------------------------- /ui/_chartbuilder-options.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('chartbuilderOptions', []); 4 | -------------------------------------------------------------------------------- /ui/chart.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc module 5 | * @name chartbuilderCharts 6 | * @description chartbuilderCharts: Render chartbuilder charts in templates 7 | * @example 8 | 9 | 10 | 16 |
17 |
18 |
19 | */ 20 | 21 | angular 22 | 23 | .module('chartbuilderCharts', ['datamaps', 'chartbuilder.nvd3', 'chartbuilderOptions']) 24 | 25 | .value('pageCharts', {}) 26 | 27 | .directive('chartbuilderChart', ['$compile', function($compile) { 28 | return { 29 | restrict: 'EA', 30 | scope: { 31 | data: '=?' 32 | }, 33 | 34 | link: function(scope, element) { 35 | scope.dataStore = scope.data; 36 | 37 | // Define child scope and template 38 | var childScope = scope.$new(); 39 | 40 | // Define build template function 41 | scope.build = function(_scope) { 42 | var template = [ 43 | '

{{ data.meta.title }}

', 44 | '

{{ data.meta.subtitle }}

', 45 | scope.data.template, 46 | '

{{ data.meta.caption }}

', 47 | '
{{ data.meta.attribution }}
' 48 | ].join(''); 49 | element.html('').append($compile(template)(_scope)); 50 | }; 51 | 52 | // Refresh directive when data changes 53 | scope.$watch('data', function(data) { 54 | if (angular.isUndefined(data) || angular.isUndefined(data.template)) { 55 | return false; 56 | } 57 | childScope.$destroy(); 58 | childScope = scope.$new(); 59 | scope.build(childScope); 60 | }, true); 61 | 62 | // Build template view 63 | //scope.build(childScope); 64 | } 65 | }; 66 | }]) 67 | 68 | .controller('chartbuilderUICtrl', ['$scope', 'pageCharts', function($scope, pageCharts) { 69 | $scope.pageCharts = pageCharts; 70 | }]); 71 | 72 | angular.element(document).ready(function() { 73 | angular.bootstrap(document, ['chartbuilderCharts']); 74 | }); 75 | --------------------------------------------------------------------------------