tufted-rails 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []