tufted-rails 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 327ac673e02c42119ebc487a18d4740b30decf8a
4
+ data.tar.gz: b673f2c19b52377868953f287819a4ae47b9e698
5
+ SHA512:
6
+ metadata.gz: 849416507e5bb5270aa9b0d34255b062440deaea05c60abc77c2ec0dd18d4c299ca274d63057e658b245bb15c21564e020f90ada26cc670cc585741bb010c34d
7
+ data.tar.gz: d89ec405fe9436e3f37abea8bfcfe649c237757e5222123f213e3307756154694a10c1dc290023d12b2a4b5f2b3258e75f5400eade48f5f892c4dab5e3517339
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ Gemfile.lock
3
+
4
+ .DS_Store
5
+
6
+ tufted-css-src
7
+ tufted-src
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ tufted-rails
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0-p247
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tufted-rails.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Tufted JS for Rails
2
+
3
+ ### Terse D3 Charts
4
+
5
+ tufted-rails integrates [Tufted.js][tufted] by [allthesignals](https://github.com/allthesignals) with the Rails 3 assets pipeline.
6
+
7
+ [tufted]: https://github.com/MAPC/tufted.js
8
+
9
+ http://github.com/mapc/tufted-rails
10
+
11
+ http://github.com/mapc/tufted.js
12
+
13
+ ## Rails > 3.1
14
+
15
+ Include tufted-rails in Gemfile:
16
+
17
+ ``` ruby
18
+ gem 'tufted-rails'
19
+ ```
20
+
21
+ or you can install from latest build:
22
+
23
+ ``` ruby
24
+ gem 'tufted-rails', require: 'tufted-rails',
25
+ git: 'git://github.com/mapc/tufted-rails.git'
26
+ ```
27
+
28
+ and run `bundle install`.
29
+
30
+
31
+ ## Setup with Rails
32
+
33
+ Add this line to `app/assets/javascripts/application.js`
34
+
35
+ ```javascript
36
+ //= require tufted-rails
37
+ ```
38
+
39
+ Add the following line to `app/assets/stylesheets/application.css` to get a simple styling.
40
+
41
+
42
+ ```css
43
+ *= require tufted-rails
44
+ ```
45
+
46
+ ## Using tufted-rails
47
+
48
+ To come. We're still preparing the final build and the website.
49
+
50
+
51
+ ## Contributing
52
+
53
+ Feel free to add issues to this repository if you find a bug or would like a feature.
54
+
55
+ To contribute code, fork this repository and issue a pull request.
56
+
57
+
58
+ ## License
59
+
60
+ The MIT License (MIT)
61
+
62
+ Copyright (c) 2014 Metropolitan Area Planning Council
63
+
64
+ Permission is hereby granted, free of charge, to any person obtaining a copy
65
+ of this software and associated documentation files (the "Software"), to deal
66
+ in the Software without restriction, including without limitation the rights
67
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
68
+ copies of the Software, and to permit persons to whom the Software is
69
+ furnished to do so, subject to the following conditions:
70
+
71
+ The above copyright notice and this permission notice shall be included in all
72
+ copies or substantial portions of the Software.
73
+
74
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
75
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
76
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
77
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
78
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
79
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
80
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'json'
4
+ require File.expand_path('../lib/tufted-rails/version', __FILE__)
5
+
6
+ desc "Update assets"
7
+ task :update do
8
+ if Dir.exist?('tufted-src')
9
+ system("cd tufted-src && git pull && cd ..")
10
+ else
11
+ system("git clone git@github.com:MAPC/tufted.js.git tufted-src")
12
+ end
13
+
14
+ if Dir.exist?('tufted-css-src')
15
+ system("cd tufted-css-src && git pull && cd ..")
16
+ else
17
+ system("git clone git@github.com:MAPC/tufted.js-tufted.css.git tufted-css-src")
18
+ end
19
+
20
+ # Copy Javascript into vendor/assets
21
+ system("cp tufted-src/tufted.js vendor/assets/javascripts/tufted-rails/tufted.js")
22
+
23
+ # Copy stylesheet into vendor/assets
24
+ system("cp tufted-css-src/tufted.css vendor/assets/stylesheets/tufted-rails/tufted.css")
25
+
26
+ system("git status")
27
+
28
+ puts "\n"
29
+ puts "tufted.js version: #{JSON.parse(File.read('./tufted-src/package.json'))['version']}"
30
+ puts "tufted-rails version: #{TuftedRails::Rails::VERSION}"
31
+ end
32
+
33
+ desc "Build"
34
+ task "build" do
35
+ system("gem build tufted-rails.gemspec")
36
+ end
37
+
38
+ desc "Build and publish the gem"
39
+ task :publish => :build do
40
+ tags = `git tag`.split
41
+ current_version = TuftedRails::Rails::VERSION
42
+ system("git tag -a #{current_version} -m 'Release #{current_version}'") unless tags.include?(current_version)
43
+ system("gem push tufted-rails-#{current_version}.gem")
44
+ system("git push --follow-tags")
45
+ end
46
+
47
+ task :release => :publish do
48
+ end
@@ -0,0 +1,12 @@
1
+ require "rails"
2
+ require "tufted-rails/version"
3
+
4
+ module TuftedRails
5
+ module Rails
6
+ if ::Rails.version.to_s < "3.1"
7
+ require "tufted-rails/railtie"
8
+ else
9
+ require "tufted-rails/engine"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ module TuftedRails
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module TuftedRails
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module TuftedRails
2
+ module Rails
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/tufted-rails/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Matt Cloyd", "W. Matt Gardner"]
6
+ gem.email = ["mcloyd@gmail.com"]
7
+ gem.description = "Terse D3 Charts for Rails"
8
+ gem.homepage = "https://github.com/mapc/tufted-rails"
9
+ gem.summary = "Load Tufted.js (by allthesignals) into Rails asset pipeline"
10
+ gem.license = 'MIT'
11
+
12
+ gem.name = "tufted-rails"
13
+ gem.require_paths = ["lib"]
14
+ gem.files = `git ls-files`.split("\n").reject { |i| i=~/testapp/}
15
+ gem.version = TuftedRails::Rails::VERSION
16
+
17
+ gem.add_dependency "railties", ">= 3.0"
18
+ gem.add_development_dependency "bundler", ">= 1.0"
19
+ gem.add_development_dependency "rake"
20
+ gem.add_development_dependency "pry"
21
+ gem.add_development_dependency "json"
22
+ end
@@ -0,0 +1 @@
1
+ //= require ./tufted
@@ -0,0 +1,760 @@
1
+ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
+ var basechart = require('./lib/baseChart');
3
+ var barchart = require('./lib/barChart');
4
+ var groupedbarchart = require('./lib/groupedBarChart');
5
+ var linechart = require('./lib/lineChart');
6
+ var stackedbarchart = require('./lib/stackedBarChart');
7
+
8
+ module.exports = {
9
+ basechart: basechart,
10
+ barchart: barchart,
11
+ groupedbarchart: groupedbarchart,
12
+ linechart: linechart,
13
+ stackedbarchart: stackedbarchart
14
+ }
15
+ },{"./lib/barChart":2,"./lib/baseChart":3,"./lib/groupedBarChart":4,"./lib/lineChart":5,"./lib/stackedBarChart":6}],2:[function(require,module,exports){
16
+ d3.chart("BaseChart").extend("BarChart", {
17
+
18
+ initialize: function() {
19
+ var chart = this;
20
+
21
+ chart.xScale = d3.scale.ordinal().rangeRoundBands([0, chart.width()], 0.1);
22
+ chart.yScale = d3.scale.linear().range([chart.height(), 0]);
23
+ chart.color = d3.scale.category10();
24
+ chart.duration = 500;
25
+
26
+ chart.on('change:width', function(newWidth) {
27
+ chart.xScale.rangeRoundBands([0, newWidth], 0.1);
28
+ });
29
+
30
+ chart.on('change:height', function(newHeight) {
31
+ chart.yScale.range([newHeight, 0]);
32
+ });
33
+
34
+ chart.areas = {};
35
+
36
+ chart.layers = {};
37
+
38
+ chart.areas.yAxisLayer = chart.base.select('g').append('g')
39
+ .classed('ylabels', true)
40
+
41
+ chart.layers.bars = chart.base.select('g').append('g')
42
+ .classed('bars', true)
43
+
44
+ // create a layer of circles that will go into
45
+ // a new group element on the base of the chart
46
+ chart.layer('bars', chart.layers.bars, {
47
+
48
+ // select the elements we wish to bind to and
49
+ // bind the data to them.
50
+ dataBind: function(data) {
51
+
52
+ var yAxis = d3.svg.axis()
53
+ .scale(chart.yScale)
54
+ .tickSize(-(chart.width()), 0, 0)
55
+ .orient("left")
56
+ .tickFormat(d3.format(".2s"));
57
+
58
+ chart.areas.yAxisLayer
59
+ .call(yAxis)
60
+ .append("text")
61
+ .attr("transform", "rotate(-90)")
62
+ .attr("y", -35)
63
+ .attr("dy", ".71em")
64
+ .style("text-anchor", "end")
65
+ .text("Percent");
66
+
67
+ var xAxis = d3.svg.axis()
68
+ .scale(chart.xScale)
69
+ .orient("bottom");
70
+
71
+ chart.base.select('g').append('g')
72
+ .classed('x axis',true)
73
+ .attr("transform", "translate(0," + chart.height() + ")")
74
+ .call(xAxis)
75
+ .selectAll("text")
76
+ .call(chart.wrap, 50)
77
+
78
+ return this.selectAll('.bar')
79
+ .data(data);
80
+ },
81
+
82
+ // insert actual rects
83
+ insert: function() {
84
+ return this.append('rect')
85
+ .attr('class', function(d,i){
86
+ return "bar-" + i;
87
+ });
88
+ },
89
+
90
+
91
+ // define lifecycle events
92
+ events: {
93
+ 'enter': function() {
94
+ var chart = this.chart();
95
+
96
+ this.attr('x', function(d) { return chart.xScale(d.name); })
97
+ .attr("title", function(d) { return d.name })
98
+ .attr("data-content", function(d) { return "Estimate: " + d.value + '%' })
99
+ .attr('y', function(d) { return chart.yScale(0); })
100
+ .attr('fill', function(d) {return chart.color(d.name);})
101
+ .attr('width', chart.xScale.rangeBand())
102
+ .attr('height', 0);
103
+ },
104
+
105
+ 'enter:transition': function() {
106
+ var chart = this.chart();
107
+
108
+ this.duration(chart.duration)
109
+ .attr('y', function(d) { return chart.yScale(d3.max([0, d.value])); })
110
+ .attr('height', function(d) { return Math.abs(chart.yScale(d.value) - chart.yScale(0)); });
111
+
112
+ $(document).ready(function () {
113
+ $("svg rect").popover({
114
+ 'container': 'body',
115
+ 'placement': 'right',
116
+ 'trigger': 'hover',
117
+ 'html': true
118
+ });
119
+ });
120
+ }
121
+ }
122
+ });
123
+
124
+
125
+
126
+ },
127
+ // set/get the color to use for the circles as they are
128
+ // rendered.
129
+ transform: function(data) {
130
+ var chart = this;
131
+
132
+ // // update the scales
133
+ chart.xScale.domain(data.map(function(d) { return d.name; }));
134
+ chart.yScale.domain(d3.extent(data, function(d) {return d.value;}));
135
+
136
+ return data;
137
+ }
138
+ });
139
+ },{}],3:[function(require,module,exports){
140
+ d3.chart("BaseChart", {
141
+
142
+ initialize: function () {
143
+ this._margin = {top: 20, right: 20, bottom: 90, left: 40};
144
+ this._width = this.base.attr('width') ? this.base.attr('width') - this._margin.left - this._margin.right : 20;
145
+ this._height = this.base.attr('height') ? this.base.attr('height') - this._margin.top - this._margin.bottom : 20;
146
+
147
+ this.updateContainerWidth();
148
+ this.updateContainerHeight();
149
+
150
+ this.base.append('g')
151
+ .attr('transform', 'translate(' + this._margin.left + ',' + this._margin.top + ')');
152
+ },
153
+
154
+ updateContainerWidth: function() { this.base.attr('width', this._width + this._margin.left + this._margin.right); },
155
+
156
+ updateContainerHeight: function() { this.base.attr('height', this._height + this._margin.top + this._margin.bottom); },
157
+
158
+ width: function(newWidth) {
159
+ if (arguments.length === 0) {
160
+ return this._width;
161
+ }
162
+
163
+ // only if the width actually changed:
164
+ if (this._width !== newWidth) {
165
+
166
+ var oldWidth = this._width;
167
+
168
+ this._width = newWidth;
169
+
170
+ // set higher container width
171
+ this.updateContainerWidth();
172
+
173
+ // trigger a change event
174
+ this.trigger('change:width', newWidth, oldWidth);
175
+ }
176
+
177
+ // always return the chart, for chaining magic.
178
+ return this;
179
+ },
180
+
181
+ height: function(newHeight) {
182
+ if (arguments.length === 0) {
183
+ return this._height;
184
+ }
185
+
186
+ var oldHeight = this._height;
187
+
188
+ this._height = newHeight;
189
+
190
+ if (this._height !== oldHeight) {
191
+
192
+ this.updateContainerHeight();
193
+
194
+ this.trigger('change:height', newHeight, oldHeight);
195
+ }
196
+
197
+ return this;
198
+ },
199
+
200
+ parseDate: function(string) {
201
+
202
+ this.parseDate = d3.time.format("%Y").parse;
203
+ return this.parseDate(string);
204
+ },
205
+
206
+ wrap: function(text, width) {
207
+ text.each(function() {
208
+ var text = d3.select(this),
209
+ words = text.text().split(/\s+/).reverse(),
210
+ word,
211
+ line = [],
212
+ lineNumber = 0,
213
+ lineHeight = 1.1, // ems
214
+ y = text.attr("y"),
215
+ dy = parseFloat(text.attr("dy")),
216
+ tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
217
+ while (word = words.pop()) {
218
+ line.push(word);
219
+ tspan.text(line.join(" "));
220
+ if (tspan.node().getComputedTextLength() > width) {
221
+ line.pop();
222
+ tspan.text(line.join(" "));
223
+ line = [word];
224
+ tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
225
+ }
226
+ }
227
+ });
228
+ }
229
+ });
230
+ },{}],4:[function(require,module,exports){
231
+ d3.chart('BaseChart').extend('GroupedBarChart', {
232
+ initialize : function() {
233
+ var chart = this;
234
+
235
+ chart.xScale = d3.scale.ordinal()
236
+ .rangeRoundBands([0, chart.width()], 0.1);
237
+ chart.x1Scale = d3.scale.ordinal();
238
+ chart.yScale = d3.scale.linear()
239
+ .range([chart.height(), 0]);
240
+ chart.color = d3.scale.category10();
241
+ chart.duration = 500;
242
+
243
+ chart.yAxis = d3.svg.axis()
244
+ .scale(chart.yScale)
245
+ .tickSize(-chart.width(), 0, 0)
246
+ .orient("left")
247
+ .tickFormat(d3.format(".2s"));
248
+
249
+ chart.on("change:width", function(newWidth) {
250
+ chart.xScale.rangeRoundBands([0, newWidth], 0.1);
251
+ });
252
+
253
+ chart.on("change:height", function(newHeight) {
254
+ chart.yScale.range([newHeight, 0]);
255
+ });
256
+
257
+
258
+ chart.areas = {};
259
+
260
+ // cache for selections that are layer bases.
261
+ chart.layers = {};
262
+
263
+ chart.areas.yAxisLayer = chart.base.select('g').append('g')
264
+ .classed('ylabels', true)
265
+
266
+ // -- actual layers
267
+ chart.layers.bars = chart.base.select('g').append('g')
268
+ .classed('bars', true)
269
+
270
+ chart.layer('bars', chart.layers.bars, {
271
+ dataBind: function(data) {
272
+ var chart = this.chart();
273
+
274
+ var yAxis = d3.svg.axis()
275
+ .scale(chart.yScale)
276
+ .tickSize(-(chart.width()), 0, 0)
277
+ .orient("left")
278
+ .tickFormat(d3.format(".2s"));
279
+
280
+ chart.areas.yAxisLayer
281
+ .call(yAxis)
282
+ .append("text")
283
+ .attr("transform", "rotate(-90)")
284
+ .attr("y", -35)
285
+ .attr("dy", ".71em")
286
+ .style("text-anchor", "end")
287
+ .text("Percent");
288
+
289
+ var xAxis = d3.svg.axis()
290
+ .scale(chart.xScale)
291
+ .orient("bottom");
292
+
293
+ chart.base.select('g').append('g')
294
+ .classed('x axis', true)
295
+ .attr("transform", "translate(0," + chart.height() + ")")
296
+ .call(xAxis)
297
+ .selectAll("text")
298
+ .call(chart.wrap, chart.xScale.rangeBand())
299
+
300
+ // Bind the data
301
+ return this.selectAll('.category')
302
+ .data(data);
303
+ },
304
+
305
+ insert: function() {
306
+ var chart = this.chart();
307
+
308
+ // Append the bars
309
+ return this.append('g')
310
+ .attr('class', 'category');
311
+ },
312
+
313
+ events: {
314
+
315
+ "enter": function() {
316
+ var chart = this.chart();
317
+
318
+ this.attr("transform", function(d, i) { return "translate(" + chart.xScale(d.series) + ",0)"; })
319
+ .selectAll(".bar")
320
+ .data(function(d) {return d.values;})
321
+ .enter()
322
+ .append("rect")
323
+ .attr("title", function(d) { return d.name })
324
+ .attr("data-content", function(d) { return "Estimate: " + d.value + '%' })
325
+ .attr('class', 'bar')
326
+ .attr("width", chart.x1Scale.rangeBand())
327
+ .style("fill", function(d) { return chart.color(d.name); })
328
+ .attr("x", function(d) { return chart.x1Scale(d.name); })
329
+ .attr("y", chart.height())
330
+ .attr("height", 0);
331
+
332
+ this.selectAll("text")
333
+ .data(function(d) { return d.values})
334
+ .enter().append("text")
335
+ .style("text-anchor", "middle")
336
+ .attr("x", function(d) { return chart.x1Scale(d.name) + chart.x1Scale.rangeBand()/2 })
337
+ .attr("y", function(d) { return chart.yScale(d.value/2); })
338
+ .text(function(d) { return d.value })
339
+
340
+ this.selectAll("line")
341
+ .data(function(d) { return d.values })
342
+ .enter().append("line")
343
+ .attr("class", "error")
344
+ .attr("x1", function(d) { return chart.x1Scale(d.name) + (chart.x1Scale.rangeBand()/2); })
345
+ .attr("y1", function(d) { return chart.yScale((d.value + d.error)) })
346
+ .attr("x2", function(d) { return chart.x1Scale(d.name) + (chart.x1Scale.rangeBand()/2); })
347
+ .attr("y2", function(d) { return chart.yScale((d.value - d.error)) })
348
+ },
349
+
350
+ "merge:transition": function() {
351
+ var chart = this.chart();
352
+
353
+ this.duration(chart.duration)
354
+ .attr("transform", function(d, i) {return "translate(" + chart.xScale(d.series) + ",0)"; })
355
+ .selectAll(".bar")
356
+ .attr("width", chart.x1Scale.rangeBand())
357
+ .attr("x", function(d) { return chart.x1Scale(d.name); })
358
+ .attr("y", function(d, i) { return chart.yScale(d.value); })
359
+ .attr("height", function(d, i) { return chart.height() - chart.yScale(d.value); });
360
+
361
+ $(document).ready(function () {
362
+ $("svg rect").popover({
363
+ 'container': 'body',
364
+ 'placement': 'right',
365
+ 'trigger': 'hover',
366
+ 'html': true
367
+ });
368
+ });
369
+ }
370
+ },
371
+ });
372
+
373
+ },
374
+
375
+ transform: function(data) {
376
+ var _data = data;
377
+
378
+ var chart = this;
379
+
380
+ chart.xScale.domain(_data.map(function(d) { return d.series; }));
381
+ chart.x1Scale.domain(['2000', '2007-11']).rangeRoundBands([0, chart.xScale.rangeBand()]);
382
+ chart.yScale.domain([0, d3.max(_data, function(d) { return d3.max(d.values, function(d) { return d.value; }); })]);
383
+
384
+ return data;
385
+ }
386
+ });
387
+ },{}],5:[function(require,module,exports){
388
+ d3.chart("BaseChart").extend("LineChart", {
389
+
390
+ initialize: function() {
391
+ var chart = this;
392
+
393
+ chart._callouts = [];
394
+
395
+ chart.xScale = d3.time.scale()
396
+ .range([0, chart.width()]);
397
+ chart.yScale = d3.scale.linear()
398
+ .range([chart.height(), 0]);
399
+ chart.color = d3.scale.category10();
400
+
401
+ chart.renderLine = d3.svg.line()
402
+ .x(function(d) { return chart.xScale(d.year); })
403
+ .y(function(d) { return chart.yScale(d.value); });
404
+
405
+ chart.duration = 500;
406
+
407
+ chart.on('change:width', function(newWidth) {
408
+ chart.xScale.range([0, newWidth]);
409
+ });
410
+
411
+ chart.on('change:height', function(newHeight) {
412
+ chart.yScale.range([newHeight, 0]);
413
+ });
414
+
415
+ chart.areas = {};
416
+
417
+ chart.layers = {};
418
+
419
+ chart.areas.yAxisLayer = chart.base.select('g').append('g')
420
+ .classed('ylabels', true)
421
+
422
+ chart.layers.lines = chart.base.select('g').append('g')
423
+ .classed('lines', true)
424
+
425
+ chart.layers.circles = chart.base.select('g').append('g')
426
+ .classed('circles', true)
427
+
428
+ chart.layers.labels = chart.base.select('g').append('g')
429
+ .classed('text-labels', true)
430
+
431
+ // create a layer of circles that will go into
432
+ // a new group element on the base of the chart
433
+ chart.layer('lines', chart.layers.lines, {
434
+
435
+ // select the elements we wish to bind to and
436
+ // bind the data to them.
437
+ dataBind: function(data) {
438
+ var chart = this.chart();
439
+
440
+ var yAxis = d3.svg.axis()
441
+ .scale(chart.yScale)
442
+ .tickSize(-chart.width(), 0, 0)
443
+ .orient("left");
444
+
445
+ chart.areas.yAxisLayer
446
+ .call(yAxis)
447
+ .append("text")
448
+ .attr("transform", "rotate(-90)")
449
+ .attr("y", -35)
450
+ .attr("dy", ".71em")
451
+ .style("text-anchor", "end")
452
+ .text("Percent");
453
+
454
+ var xAxis = d3.svg.axis()
455
+ .scale(chart.xScale)
456
+ .orient("bottom");
457
+
458
+ chart.base.select('g').append('g')
459
+ .classed('x axis', true)
460
+ .attr("transform", "translate(0," + chart.height() + ")")
461
+ .call(xAxis)
462
+ .selectAll("text")
463
+ .call(chart.wrap, 50)
464
+
465
+ return this.selectAll('.line')
466
+ .data(data);
467
+ },
468
+
469
+ // insert actual rects
470
+ insert: function() {
471
+ return this.append('path')
472
+ .attr('class', function(d,i) {
473
+ return "line-" + i;
474
+ });
475
+ },
476
+
477
+ // define lifecycle events
478
+ events: {
479
+ 'enter': function() {
480
+ var chart = this.chart();
481
+ this.attr('d', function(d) { return chart.renderLine(d.values); })
482
+ .attr("class", "line")
483
+ .style("stroke", function(d) {
484
+ if (chart.matchWithCallouts(d.series) || chart.callouts() == false) {
485
+ return chart.color(d.series)
486
+ } else {
487
+ return "Lightgray"
488
+ }
489
+ })
490
+ .on("mouseover", function(d,i) {
491
+ d3.select(this)
492
+ .style("stroke-width", "7");
493
+ })
494
+ .on("mouseout", function(d,i) {
495
+ d3.select(this)
496
+ .transition()
497
+ .duration(350)
498
+ .style("stroke-width", "3");
499
+ });
500
+
501
+ // this.append("text")
502
+ // .datum(function(d) { return { name: d.series, value: d.values[d.values.length - 1] }; })
503
+ // .attr("transform", function(d) { return "translate(" + (chart.xScale(d.value.year) + 10) + "," + chart.yScale(d.value.value) + ")"; })
504
+ // .attr("x", 3)
505
+ // .attr("dy", ".15em")
506
+ // .attr("id", function(d,i) { return "label" + i })
507
+ // .text(function(d) { return d.name; });
508
+ },
509
+
510
+ 'enter:transition': function() {
511
+ var chart = this.chart();
512
+
513
+ // this.duration(chart.duration)
514
+ // .attr('y', function(d) { return chart.yScale(d3.max([0, d.value])); })
515
+ // .attr('height', function(d) { return Math.abs(chart.yScale(d.value) - chart.yScale(0)); });
516
+
517
+ $(document).ready(function () {
518
+ $("svg circle").popover({
519
+ 'container': 'body',
520
+ 'placement': 'right',
521
+ 'trigger': 'hover',
522
+ 'html': true
523
+ });
524
+ });
525
+ }
526
+ }
527
+ });
528
+
529
+ chart.layer('circles', chart.layers.circles, {
530
+
531
+ dataBind: function(data) {
532
+ return this.selectAll("circles")
533
+ .data(data);
534
+ },
535
+
536
+ insert: function() {
537
+ return this.append('g')
538
+ .attr('class', 'data-points');
539
+ },
540
+
541
+ events: {
542
+
543
+ 'enter': function () {
544
+
545
+ var chart = this.chart();
546
+
547
+ this.selectAll("circle")
548
+ .data(function(d) {return d.values; })
549
+ .enter()
550
+ .append("svg:circle")
551
+ .attr("r", 3)
552
+ .attr("cx", function(d) { return chart.xScale(d.year) })
553
+ .attr("cy", function(d) { return chart.yScale(d.value) })
554
+ .attr("title", function(d) { return (d.year).getFullYear() })
555
+ .attr("data-content", function(d) { return "Estimate: " + d.value + "%" })
556
+ .attr("fill", "black")
557
+ .on("mouseover", function(d, i) {
558
+ d3.select(this)
559
+ .attr("r", "6");
560
+ })
561
+ .on("mouseout", function(d) {
562
+ d3.select(this)
563
+ .transition()
564
+ .duration(150)
565
+ .attr("r", "3")
566
+ });
567
+ },
568
+
569
+ 'enter:transition': function () {
570
+ $(document).ready( function () {
571
+ $("svg circle").popover({
572
+ 'container': 'body',
573
+ 'placement': 'right',
574
+ 'trigger': 'hover',
575
+ 'html': true
576
+ });
577
+ });
578
+ }
579
+ }
580
+ });
581
+
582
+ chart.layer('text-labels', chart.layers.labels, {
583
+ dataBind: function(data) {
584
+ return this.selectAll("text-labels")
585
+ .data(data);
586
+ },
587
+
588
+ insert: function () {
589
+ return this.append("text")
590
+ .attr("class", "text-labels")
591
+
592
+ },
593
+ events: {
594
+ 'enter': function () {
595
+ var chart = this.chart();
596
+
597
+ this.attr("transform", function(d,i) { return "translate(" + (chart.xScale((d.values[d.values.length - 1]).year) + 10) + "," + chart.yScale((d.values[d.values.length - 1]).value) + ")"; })
598
+ .attr("x", 3)
599
+ .attr("dy", ".15em")
600
+ .attr("id", function(d,i) { return "label" + i })
601
+ .text(function(d) { return d.series; });
602
+
603
+ }
604
+ }
605
+ });
606
+
607
+ },
608
+
609
+ callouts: function(collection) {
610
+ if (arguments.length === 0) {
611
+ return this._callouts;
612
+ }
613
+
614
+ if (Array.isArray(collection)) {
615
+ this._callouts = collection
616
+ }
617
+
618
+ return this;
619
+ },
620
+
621
+ matchWithCallouts: function (comparator) {
622
+ return this._callouts.indexOf(comparator) !== -1
623
+ },
624
+
625
+ // set/get the color to use for the circles as they are
626
+ // rendered.
627
+ transform: function(data) {
628
+ var chart = this;
629
+ // update the scales
630
+
631
+ chart.xScale.domain(d3.extent([2005,2006,2007,2008,2009,2010,2011,2012].map(function(d) { return chart.parseDate(d.toString()) })));
632
+ chart.yScale.domain([30,60]);
633
+
634
+ return data;
635
+ }
636
+ });
637
+ },{}],6:[function(require,module,exports){
638
+ d3.chart('BaseChart').extend('StackedBarChart', {
639
+ initialize : function() {
640
+ var chart = this;
641
+
642
+ chart.xScale = d3.scale.ordinal()
643
+ .rangeRoundBands([0, chart.width()], .1);
644
+ chart.yScale = d3.scale.linear()
645
+ .rangeRound([chart.height(), 0]);
646
+ chart.color = d3.scale.category10();
647
+ chart.duration = 500;
648
+
649
+ chart.yAxis = d3.svg.axis()
650
+ .scale(chart.yScale)
651
+ .tickSize(-chart.width(), 0, 0)
652
+ .orient("left")
653
+ .tickFormat(d3.format(".2s"));
654
+
655
+ chart.on("change:width", function(newWidth) {
656
+ chart.xScale.rangeRoundBands([0, newWidth], 0.1);
657
+ });
658
+
659
+ chart.on("change:height", function(newHeight) {
660
+ chart.yScale.range([newHeight, 0]);
661
+ });
662
+
663
+
664
+ chart.areas = {};
665
+
666
+ // cache for selections that are layer bases.
667
+ chart.layers = {};
668
+
669
+ chart.areas.yAxisLayer = chart.base.select('g').append('g')
670
+ .classed('ylabels', true)
671
+
672
+ // -- actual layers
673
+ chart.layers.bars = chart.base.select('g').append('g')
674
+ .classed('bars', true)
675
+
676
+ chart.layer('bars', chart.layers.bars, {
677
+ dataBind: function(data) {
678
+ var chart = this.chart();
679
+
680
+ var yAxis = d3.svg.axis()
681
+ .scale(chart.yScale)
682
+ .tickSize(-(chart.width()), 0, 0)
683
+ .orient("left")
684
+ .tickFormat(d3.format(".2s"));
685
+
686
+ chart.areas.yAxisLayer
687
+ .call(yAxis)
688
+ .append("text")
689
+ .attr("transform", "rotate(-90)")
690
+ .attr("y", -35)
691
+ .attr("dy", ".71em")
692
+ .style("text-anchor", "end")
693
+ .text("Percent");
694
+
695
+ var xAxis = d3.svg.axis()
696
+ .scale(chart.xScale)
697
+ .orient("bottom");
698
+
699
+ chart.base.select('g').append('g')
700
+ .classed('x axis', true)
701
+ .attr("transform", "translate(0," + chart.height() + ")")
702
+ .call(xAxis)
703
+ .selectAll("text")
704
+ .call(chart.wrap, chart.xScale.rangeBand())
705
+
706
+ // Bind the data
707
+ return this.selectAll('.category')
708
+ .data(data);
709
+ },
710
+
711
+ insert: function() {
712
+ var chart = this.chart();
713
+
714
+ // Append the bars
715
+ return this.append('g')
716
+ .attr('class', 'category');
717
+ },
718
+
719
+ events: {
720
+
721
+ "enter": function() {
722
+ var chart = this.chart();
723
+
724
+ this.attr("transform", function(d, i) { return "translate(" + chart.xScale(d.State) + ",0)"; })
725
+ .selectAll(".category")
726
+ .data(function(d) { return d.groups; })
727
+ .enter().append("rect")
728
+ .attr("class", "bar")
729
+ // .attr("transform", function(d) { return "translate(" + chart.xScale(d.State) + ",0)"; })
730
+ .attr("width", chart.xScale.rangeBand())
731
+ .attr("y", function(d) { return chart.yScale(d.y1); })
732
+ .attr("height", function(d) { return chart.yScale(d.y0) - chart.yScale(d.y1); })
733
+ .style("fill", function(d) { return chart.color(d.name); });
734
+ }
735
+ },
736
+ });
737
+
738
+ },
739
+
740
+ transform: function(data) {
741
+ var _data = data;
742
+ var chart = this;
743
+
744
+ chart.color.domain(d3.keys(data[0]).filter(function(key) { return key !== "State"; }));
745
+
746
+ _data.forEach(function(d) {
747
+ var y0 = 0;
748
+ d.groups = chart.color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
749
+ d.total = d.groups[d.groups.length - 1].y1;
750
+ });
751
+
752
+ data.sort(function(a, b) { return b.total - a.total; });
753
+
754
+ chart.xScale.domain(data.map(function(d) { return d.State; }));
755
+ chart.yScale.domain([0, d3.max(data, function(d) { return d.total; })]);
756
+
757
+ return data;
758
+ }
759
+ });
760
+ },{}]},{},[1])
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require ./tufted.css
3
+ */
@@ -0,0 +1,70 @@
1
+ text {
2
+ font: 10px sans-serif;
3
+ }
4
+
5
+ .charts {
6
+ height:300px;
7
+ width:400px;
8
+ }
9
+
10
+ body {
11
+ font: 12px sans-serif;
12
+ }
13
+
14
+ circle:hover {
15
+ cursor: pointer;
16
+ }
17
+
18
+ path:hover {
19
+ cursor: pointer;
20
+ }
21
+
22
+ .category text {
23
+ fill: white;
24
+ }
25
+
26
+ .axis path,
27
+ .axis line {
28
+ fill: none;
29
+ stroke: #000;
30
+ shape-rendering: crispEdges;
31
+ }
32
+
33
+ .recession {
34
+ fill: lightgrey;
35
+ }
36
+
37
+ .line {
38
+ fill: none;
39
+ stroke: steelblue;
40
+ stroke-width: 3px;
41
+ }
42
+
43
+ .tick.major line {
44
+ stroke: lightgrey;
45
+ /*opacity: 0.7;*/
46
+ }
47
+
48
+ .bar {
49
+ fill: steelblue;
50
+ }
51
+
52
+ .error {
53
+ stroke: black;
54
+ stroke-width:2;
55
+ }
56
+
57
+ .average {
58
+
59
+ stroke-width:2;
60
+
61
+ }
62
+
63
+ #average0 {
64
+ stroke: black;
65
+ stroke-dasharray: 6, 1;
66
+ }
67
+
68
+ #average1 {
69
+ stroke: black;
70
+ }
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tufted-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Matt Cloyd
8
+ - W. Matt Gardner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '3.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '3.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '1.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '1.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: json
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: Terse D3 Charts for Rails
85
+ email:
86
+ - mcloyd@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .ruby-gemset
93
+ - .ruby-version
94
+ - Gemfile
95
+ - README.md
96
+ - Rakefile
97
+ - lib/tufted-rails.rb
98
+ - lib/tufted-rails/engine.rb
99
+ - lib/tufted-rails/railtie.rb
100
+ - lib/tufted-rails/version.rb
101
+ - tufted-rails.gemspec
102
+ - vendor/assets/javascripts/tufted-rails/index.js
103
+ - vendor/assets/javascripts/tufted-rails/tufted.js
104
+ - vendor/assets/stylesheets/tufted-rails/index.css
105
+ - vendor/assets/stylesheets/tufted-rails/tufted.css
106
+ homepage: https://github.com/mapc/tufted-rails
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.1.10
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Load Tufted.js (by allthesignals) into Rails asset pipeline
130
+ test_files: []