├── html
├── scripts
│ ├── rickshaw
│ │ ├── .gitignore
│ │ ├── examples
│ │ │ ├── images
│ │ │ │ ├── om_bar.png
│ │ │ │ ├── om_lines.png
│ │ │ │ ├── om_stack.png
│ │ │ │ ├── om_step.png
│ │ │ │ ├── interp_step.png
│ │ │ │ ├── offset_pct.png
│ │ │ │ ├── om_curves.png
│ │ │ │ ├── om_percent.png
│ │ │ │ ├── om_scatter.png
│ │ │ │ ├── om_stream.png
│ │ │ │ ├── interp_linear.png
│ │ │ │ ├── offset_stack.png
│ │ │ │ ├── offset_stream.png
│ │ │ │ ├── offset_value.png
│ │ │ │ └── interp_cardinal.png
│ │ │ ├── screenshots
│ │ │ │ ├── ajax.png
│ │ │ │ ├── colors.png
│ │ │ │ ├── lines.png
│ │ │ │ ├── simple.png
│ │ │ │ ├── start.png
│ │ │ │ ├── status.png
│ │ │ │ ├── stops.png
│ │ │ │ ├── y_axis.png
│ │ │ │ ├── extensions.png
│ │ │ │ └── scatterplot.png
│ │ │ ├── css
│ │ │ │ ├── lines.css
│ │ │ │ └── extensions.css
│ │ │ ├── data
│ │ │ │ ├── data.jsonp
│ │ │ │ ├── data.json
│ │ │ │ ├── data2.json
│ │ │ │ └── status.json
│ │ │ ├── start.html
│ │ │ ├── simple.html
│ │ │ ├── negative.html
│ │ │ ├── scatterplot.html
│ │ │ ├── ajax.html
│ │ │ ├── refresh.html
│ │ │ ├── bars.html
│ │ │ ├── inconsistent.html
│ │ │ ├── jsonp.html
│ │ │ ├── gaps.html
│ │ │ ├── y_axis.html
│ │ │ ├── status.html
│ │ │ ├── colors.html
│ │ │ ├── stops.html
│ │ │ ├── lines.html
│ │ │ ├── formatter.html
│ │ │ ├── fixed.html
│ │ │ ├── hover.html
│ │ │ ├── js
│ │ │ │ └── extensions.js
│ │ │ ├── index.html
│ │ │ └── series.html
│ │ ├── package.json
│ │ ├── src
│ │ │ ├── js
│ │ │ │ ├── Rickshaw.Graph.JSONP.js
│ │ │ │ ├── Rickshaw.Graph.Unstacker.js
│ │ │ │ ├── Rickshaw.Graph.Renderer.Line.js
│ │ │ │ ├── Rickshaw.Graph.Renderer.Stack.js
│ │ │ │ ├── Rickshaw.js
│ │ │ │ ├── Rickshaw.Fixtures.RandomData.js
│ │ │ │ ├── Rickshaw.Graph.Behavior.Series.Order.js
│ │ │ │ ├── Rickshaw.Fixtures.Number.js
│ │ │ │ ├── Rickshaw.Graph.Renderer.ScatterPlot.js
│ │ │ │ ├── Rickshaw.Graph.RangeSlider.js
│ │ │ │ ├── Rickshaw.Graph.Smoother.js
│ │ │ │ ├── Rickshaw.Graph.Legend.js
│ │ │ │ ├── Rickshaw.Color.Palette.js
│ │ │ │ ├── Rickshaw.Graph.Ajax.js
│ │ │ │ ├── Rickshaw.Graph.Behavior.Series.Highlight.js
│ │ │ │ ├── Rickshaw.Graph.Axis.Time.js
│ │ │ │ ├── Rickshaw.Series.FixedDuration.js
│ │ │ │ ├── Rickshaw.Graph.Renderer.Area.js
│ │ │ │ ├── Rickshaw.Graph.Axis.Y.js
│ │ │ │ ├── Rickshaw.Fixtures.Color.js
│ │ │ │ ├── Rickshaw.Fixtures.Time.js
│ │ │ │ ├── Rickshaw.Graph.Renderer.Bar.js
│ │ │ │ ├── Rickshaw.Graph.Annotate.js
│ │ │ │ ├── Rickshaw.Series.js
│ │ │ │ ├── Rickshaw.Graph.Renderer.js
│ │ │ │ ├── Rickshaw.Compat.ClassList.js
│ │ │ │ ├── Rickshaw.Graph.Behavior.Series.Toggle.js
│ │ │ │ ├── Rickshaw.Graph.HoverDetail.js
│ │ │ │ └── Rickshaw.Graph.js
│ │ │ └── css
│ │ │ │ ├── legend.css
│ │ │ │ ├── detail.css
│ │ │ │ └── graph.css
│ │ ├── tests
│ │ │ ├── data
│ │ │ │ └── simple.svg
│ │ │ ├── Rickshaw.Class.js
│ │ │ ├── Rickshaw.Series.FixedDuration.js
│ │ │ ├── Rickshaw.Graph.Renderer.js
│ │ │ ├── Rickshaw.Graph.js
│ │ │ └── Rickshaw.Series.js
│ │ ├── tutorial
│ │ │ ├── transform.pl
│ │ │ ├── example_01.html
│ │ │ ├── transform_epoch.pl
│ │ │ ├── example_02.html
│ │ │ ├── vendor
│ │ │ │ └── prettify
│ │ │ │ │ └── prettify.css
│ │ │ ├── transform_region.pl
│ │ │ ├── example_03.html
│ │ │ ├── example_04.html
│ │ │ ├── style.css
│ │ │ ├── example_05.html
│ │ │ ├── example_06.html
│ │ │ └── example_07.html
│ │ ├── LICENSE
│ │ ├── Makefile
│ │ └── rickshaw.min.css
│ ├── d3
│ │ └── LICENSE
│ ├── jquery-tod.js
│ ├── mapplayer
│ │ ├── frame.js
│ │ └── mapplayer.js
│ └── main.js
├── images
│ ├── loading.gif
│ └── tod
│ │ ├── 0.png
│ │ ├── 1.png
│ │ ├── 10.png
│ │ ├── 11.png
│ │ ├── 12.png
│ │ ├── 13.png
│ │ ├── 14.png
│ │ ├── 15.png
│ │ ├── 16.png
│ │ ├── 17.png
│ │ ├── 18.png
│ │ ├── 19.png
│ │ ├── 2.png
│ │ ├── 20.png
│ │ ├── 21.png
│ │ ├── 22.png
│ │ ├── 23.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.png
│ │ ├── 7.png
│ │ ├── 8.png
│ │ └── 9.png
└── img
│ ├── glyphicons-halflings.png
│ └── glyphicons-halflings-white.png
├── README.md
├── clean_incidents.php
├── json_calls.php
└── clean_calls.php
/html/scripts/rickshaw/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | *swp
3 | node_modules
4 |
--------------------------------------------------------------------------------
/html/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/loading.gif
--------------------------------------------------------------------------------
/html/images/tod/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/0.png
--------------------------------------------------------------------------------
/html/images/tod/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/1.png
--------------------------------------------------------------------------------
/html/images/tod/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/10.png
--------------------------------------------------------------------------------
/html/images/tod/11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/11.png
--------------------------------------------------------------------------------
/html/images/tod/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/12.png
--------------------------------------------------------------------------------
/html/images/tod/13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/13.png
--------------------------------------------------------------------------------
/html/images/tod/14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/14.png
--------------------------------------------------------------------------------
/html/images/tod/15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/15.png
--------------------------------------------------------------------------------
/html/images/tod/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/16.png
--------------------------------------------------------------------------------
/html/images/tod/17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/17.png
--------------------------------------------------------------------------------
/html/images/tod/18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/18.png
--------------------------------------------------------------------------------
/html/images/tod/19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/19.png
--------------------------------------------------------------------------------
/html/images/tod/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/2.png
--------------------------------------------------------------------------------
/html/images/tod/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/20.png
--------------------------------------------------------------------------------
/html/images/tod/21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/21.png
--------------------------------------------------------------------------------
/html/images/tod/22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/22.png
--------------------------------------------------------------------------------
/html/images/tod/23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/23.png
--------------------------------------------------------------------------------
/html/images/tod/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/3.png
--------------------------------------------------------------------------------
/html/images/tod/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/4.png
--------------------------------------------------------------------------------
/html/images/tod/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/5.png
--------------------------------------------------------------------------------
/html/images/tod/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/6.png
--------------------------------------------------------------------------------
/html/images/tod/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/7.png
--------------------------------------------------------------------------------
/html/images/tod/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/8.png
--------------------------------------------------------------------------------
/html/images/tod/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/images/tod/9.png
--------------------------------------------------------------------------------
/html/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/html/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_bar.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_lines.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_stack.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_step.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_step.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/interp_step.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/interp_step.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/offset_pct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/offset_pct.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_curves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_curves.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_percent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_percent.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_scatter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_scatter.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/om_stream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/om_stream.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/ajax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/ajax.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/colors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/colors.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/lines.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/simple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/simple.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/start.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/status.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/status.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/stops.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/stops.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/y_axis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/y_axis.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/interp_linear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/interp_linear.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/offset_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/offset_stack.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/offset_stream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/offset_stream.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/offset_value.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/offset_value.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/images/interp_cardinal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/images/interp_cardinal.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/extensions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/extensions.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/screenshots/scatterplot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mwinters0/crimeline/master/html/scripts/rickshaw/examples/screenshots/scatterplot.png
--------------------------------------------------------------------------------
/html/scripts/rickshaw/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rickshaw",
3 | "version": "1.1.2",
4 | "dependencies": {
5 | "d3": ">= 2.10.1"
6 | },
7 | "keywords": ["d3", "charts", "rickshaw", "svg", "graph"],
8 | "main": "./rickshaw",
9 | "engines": {
10 | "node": ">= 0.8.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.JSONP.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.JSONP');
2 |
3 | Rickshaw.Graph.JSONP = Rickshaw.Class.create( Rickshaw.Graph.Ajax, {
4 |
5 | request: function() {
6 |
7 | $.ajax( {
8 | url: this.dataURL,
9 | dataType: 'jsonp',
10 | success: this.success.bind(this),
11 | error: this.error.bind(this)
12 | } );
13 | }
14 | } );
15 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/css/lines.css:
--------------------------------------------------------------------------------
1 | div, span, p, td {
2 | font-family: Arial, sans-serif;
3 | }
4 | #chart {
5 | display: inline-block;
6 | }
7 | #legend {
8 | display: inline-block;
9 | position: relative;
10 | left: 8px;
11 | }
12 | #legend_container {
13 | position: absolute;
14 | right: 0;
15 | bottom: 26px;
16 | width: 0;
17 | }
18 | #chart_container {
19 | float: left;
20 | position: relative;
21 | }
22 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tests/data/simple.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/data/data.jsonp:
--------------------------------------------------------------------------------
1 | callback([
2 | {
3 | 'color': 'blue',
4 | 'name': 'London',
5 | 'data': [ { x: 0, y: 40 }, { x: 1, y: 49 }, { x: 2, y: 38 }, { x: 3, y: 30 }, { x: 4, y: 32 } ],
6 | }, {
7 | 'name': 'New York',
8 | 'data': [ { x: 0, y: 19 }, { x: 1, y: 22 }, { x: 2, y: 29 }, { x: 3, y: 20 }, { x: 4, y: 14 } ],
9 | }, {
10 | 'name': 'Tokyo',
11 | 'data': [ { x: 0, y: 8 }, { x: 1, y: 12 }, { x: 2, y: 15 }, { x: 3, y: 11 }, { x: 4, y: 10 } ],
12 | }
13 | ]);
14 |
15 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/data/data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "color": "blue",
4 | "name": "New York",
5 | "data": [ { "x": 0, "y": 40 }, { "x": 1, "y": 49 }, { "x": 2, "y": 38 }, { "x": 3, "y": 30 }, { "x": 4, "y": 32 } ]
6 | }, {
7 | "name": "London",
8 | "data": [ { "x": 0, "y": 19 }, { "x": 1, "y": 22 }, { "x": 2, "y": 29 }, { "x": 3, "y": 20 }, { "x": 4, "y": 14 } ]
9 | }, {
10 | "name": "Tokyo",
11 | "data": [ { "x": 0, "y": 8 }, { "x": 1, "y": 12 }, { "x": 2, "y": 15 }, { "x": 3, "y": 11 }, { "x": 4, "y": 10 } ]
12 | }
13 | ]
14 |
15 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/data/data2.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "color": "blue",
4 | "name": "New York",
5 | "data": [ { "x": 0, "y": 50 }, { "x": 1, "y": 32 }, { "x": 2, "y": 38 }, { "x": 3, "y": 30 }, { "x": 4, "y": 32 } ]
6 | }, {
7 | "name": "London",
8 | "data": [ { "x": 0, "y": 19 }, { "x": 1, "y": 76 }, { "x": 2, "y": 28 }, { "x": 3, "y": 20 }, { "x": 4, "y": 14 } ]
9 | }, {
10 | "name": "Tokyo",
11 | "data": [ { "x": 0, "y": 8 }, { "x": 1, "y": 12 }, { "x": 2, "y": 14 }, { "x": 3, "y": 11 }, { "x": 4, "y": 28 } ]
12 | }
13 | ]
14 |
15 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/start.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
24 |
25 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/transform.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env perl
2 |
3 | use warnings;
4 | use strict;
5 |
6 | my @header;
7 | my $data;
8 |
9 | while (<>) {
10 |
11 | # the third line is the header
12 | if ($. == 3) {
13 | # and we want the years
14 | @header = map { m/^(\d{4})/; $1; }
15 | (split ',')[1..11];
16 | }
17 |
18 | if (m/^United States/) {
19 | my $i = -1;
20 | $data = "[ " . join(", ", map { "{ x: $header[++$i], y: $_ }" } (split ',')[1..11]) . " ]";
21 | last;
22 | }
23 | }
24 |
25 | print $data;
26 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Unstacker.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Unstacker');
2 |
3 | Rickshaw.Graph.Unstacker = function(args) {
4 |
5 | this.graph = args.graph;
6 | var self = this;
7 |
8 | this.graph.stackData.hooks.after.push( {
9 | name: 'unstacker',
10 | f: function(data) {
11 |
12 | if (!self.graph.renderer.unstack) return data;
13 |
14 | data.forEach( function(seriesData) {
15 | seriesData.forEach( function(d) {
16 | d.y0 = 0;
17 | } );
18 | } );
19 |
20 | return data;
21 | }
22 | } );
23 | };
24 |
25 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_01.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
25 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/transform_epoch.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env perl
2 |
3 | use warnings;
4 | use strict;
5 |
6 | use Time::Local 'timegm';
7 |
8 | my @header;
9 | my $data;
10 |
11 | while (<>) {
12 |
13 | # the third line is the header
14 | if ($. == 3) {
15 | # and we want the years in epoch seconds
16 | @header = map { m/^(\d{4})/; year_to_seconds($1); }
17 | (split ',')[1..11];
18 | }
19 |
20 | if (m/^United States/) {
21 | my $i = -1;
22 | $data = "[ " . join(", ", map { "{ x: $header[++$i], y: $_ }" } (split ',')[1..11]) . " ]";
23 | last;
24 | }
25 | }
26 |
27 | sub year_to_seconds {
28 | my $year = shift;
29 | return timegm(0, 0, 0, 1, 0, $year);
30 | }
31 |
32 | print $data;
33 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Renderer.Line.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Renderer.Line');
2 |
3 | Rickshaw.Graph.Renderer.Line = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
4 |
5 | name: 'line',
6 |
7 | defaults: function($super) {
8 |
9 | return Rickshaw.extend( $super(), {
10 | unstack: true,
11 | fill: false,
12 | stroke: true
13 | } );
14 | },
15 |
16 | seriesPathFactory: function() {
17 |
18 | var graph = this.graph;
19 |
20 | var factory = d3.svg.line()
21 | .x( function(d) { return graph.x(d.x) } )
22 | .y( function(d) { return graph.y(d.y) } )
23 | .interpolate(this.graph.interpolation).tension(this.tension)
24 |
25 | factory.defined && factory.defined( function(d) { return d.y !== null } );
26 | return factory;
27 | }
28 | } );
29 |
30 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/simple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
30 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_02.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
25 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/negative.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/vendor/prettify/prettify.css:
--------------------------------------------------------------------------------
1 | /* Pretty printing styles. Used with prettify.js. */
2 |
3 | .str { color: #080; }
4 | .kwd { color: #008; }
5 | .com { color: #800; }
6 | .typ { color: #606; }
7 | .lit { color: #066; }
8 | .pun { color: #660; }
9 | .pln { color: #000; }
10 | .tag { color: #008; }
11 | .atn { color: #606; }
12 | .atv { color: #080; }
13 | .dec { color: #606; }
14 | pre.prettyprint { padding: 2px; border: 1px solid #888; }
15 |
16 | @media print {
17 | .str { color: #060; }
18 | .kwd { color: #006; font-weight: bold; }
19 | .com { color: #600; font-style: italic; }
20 | .typ { color: #404; font-weight: bold; }
21 | .lit { color: #044; }
22 | .pun { color: #440; }
23 | .pln { color: #000; }
24 | .tag { color: #006; font-weight: bold; }
25 | .atn { color: #404; }
26 | .atv { color: #060; }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/transform_region.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env perl
2 |
3 | use warnings;
4 | use strict;
5 |
6 | use Time::Local 'timegm';
7 |
8 | my @header;
9 | my $data;
10 |
11 | while (<>) {
12 |
13 | # the third line is the header
14 | if ($. == 3) {
15 | # and we want the years in epoch seconds
16 | @header = map { m/^(\d{4})/; year_to_seconds($1); }
17 | (split ',')[1..11];
18 | }
19 |
20 | if (m/^(Northeast|Midwest|South|West)/) {
21 | my $i = -1;
22 | $data .= "\n{\n\tname: \"$1\",\n";
23 | $data .= "\tdata: [ " . join(", ", map { "{ x: $header[++$i], y: $_ }" } (split ',')[1..11]) . " ],\n\n},";
24 | }
25 |
26 | chop $data && last if m/^Alabama/; # we have what we need now.
27 | }
28 |
29 | sub year_to_seconds {
30 | my $year = shift;
31 | return timegm(0, 0, 0, 1, 0, $year);
32 | }
33 |
34 | print "$data\n";
35 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Renderer.Stack.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Renderer.Stack');
2 |
3 | Rickshaw.Graph.Renderer.Stack = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
4 |
5 | name: 'stack',
6 |
7 | defaults: function($super) {
8 |
9 | return Rickshaw.extend( $super(), {
10 | fill: true,
11 | stroke: false,
12 | unstack: false
13 | } );
14 | },
15 |
16 | seriesPathFactory: function() {
17 |
18 | var graph = this.graph;
19 |
20 | var factory = d3.svg.area()
21 | .x( function(d) { return graph.x(d.x) } )
22 | .y0( function(d) { return graph.y(d.y0) } )
23 | .y1( function(d) { return graph.y(d.y + d.y0) } )
24 | .interpolate(this.graph.interpolation).tension(this.tension);
25 |
26 | factory.defined && factory.defined( function(d) { return d.y !== null } );
27 | return factory;
28 | }
29 | } );
30 |
31 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.js:
--------------------------------------------------------------------------------
1 | var Rickshaw = {
2 |
3 | namespace: function(namespace, obj) {
4 |
5 | var parts = namespace.split('.');
6 |
7 | var parent = Rickshaw;
8 |
9 | for(var i = 1, length = parts.length; i < length; i++) {
10 | var currentPart = parts[i];
11 | parent[currentPart] = parent[currentPart] || {};
12 | parent = parent[currentPart];
13 | }
14 | return parent;
15 | },
16 |
17 | keys: function(obj) {
18 | var keys = [];
19 | for (var key in obj) keys.push(key);
20 | return keys;
21 | },
22 |
23 | extend: function(destination, source) {
24 |
25 | for (var property in source) {
26 | destination[property] = source[property];
27 | }
28 | return destination;
29 | }
30 | };
31 |
32 | if (typeof module !== 'undefined' && module.exports) {
33 | var d3 = require('d3');
34 | module.exports = Rickshaw;
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Fixtures.RandomData.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Fixtures.RandomData');
2 |
3 | Rickshaw.Fixtures.RandomData = function(timeInterval) {
4 |
5 | var addData;
6 | timeInterval = timeInterval || 1;
7 |
8 | var lastRandomValue = 200;
9 |
10 | var timeBase = Math.floor(new Date().getTime() / 1000);
11 |
12 | this.addData = function(data) {
13 |
14 | var randomValue = Math.random() * 100 + 15 + lastRandomValue;
15 | var index = data[0].length;
16 |
17 | var counter = 1;
18 |
19 | data.forEach( function(series) {
20 | var randomVariance = Math.random() * 20;
21 | var v = randomValue / 25 + counter++
22 | + (Math.cos((index * counter * 11) / 960) + 2) * 15
23 | + (Math.cos(index / 7) + 2) * 7
24 | + (Math.cos(index / 17) + 2) * 1;
25 |
26 | series.push( { x: (index * timeInterval) + timeBase, y: v + randomVariance } );
27 | } );
28 |
29 | lastRandomValue = randomValue * .85;
30 | }
31 | };
32 |
33 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/scatterplot.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
44 |
45 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_03.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
28 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/ajax.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011 by Shutterstock Images, LLC
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Behavior.Series.Order.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Order');
2 |
3 | Rickshaw.Graph.Behavior.Series.Order = function(args) {
4 |
5 | this.graph = args.graph;
6 | this.legend = args.legend;
7 |
8 | var self = this;
9 |
10 | $(function() {
11 | $(self.legend.list).sortable( {
12 | containment: 'parent',
13 | tolerance: 'pointer',
14 | update: function( event, ui ) {
15 | var series = [];
16 | $(self.legend.list).find('li').each( function(index, item) {
17 | if (!item.series) return;
18 | series.push(item.series);
19 | } );
20 |
21 | for (var i = self.graph.series.length - 1; i >= 0; i--) {
22 | self.graph.series[i] = series.shift();
23 | }
24 |
25 | self.graph.update();
26 | }
27 | } );
28 | $(self.legend.list).disableSelection();
29 | });
30 |
31 | //hack to make jquery-ui sortable behave
32 | this.graph.onUpdate( function() {
33 | var h = window.getComputedStyle(self.legend.element).height;
34 | self.legend.element.style.height = h;
35 | } );
36 | };
37 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/refresh.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/bars.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Fixtures.Number.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Fixtures.Number');
2 |
3 | Rickshaw.Fixtures.Number.formatKMBT = function(y) {
4 | abs_y = Math.abs(y);
5 | if (abs_y >= 1000000000000) { return y / 1000000000000 + "T" }
6 | else if (abs_y >= 1000000000) { return y / 1000000000 + "B" }
7 | else if (abs_y >= 1000000) { return y / 1000000 + "M" }
8 | else if (abs_y >= 1000) { return y / 1000 + "K" }
9 | else if (abs_y < 1 && y > 0) { return y.toFixed(2) }
10 | else if (abs_y == 0) { return '' }
11 | else { return y }
12 | };
13 |
14 | Rickshaw.Fixtures.Number.formatBase1024KMGTP = function(y) {
15 | abs_y = Math.abs(y);
16 | if (abs_y >= 1125899906842624) { return y / 1125899906842624 + "P" }
17 | else if (abs_y >= 1099511627776){ return y / 1099511627776 + "T" }
18 | else if (abs_y >= 1073741824) { return y / 1073741824 + "G" }
19 | else if (abs_y >= 1048576) { return y / 1048576 + "M" }
20 | else if (abs_y >= 1024) { return y / 1024 + "K" }
21 | else if (abs_y < 1 && y > 0) { return y.toFixed(2) }
22 | else if (abs_y == 0) { return '' }
23 | else { return y }
24 | };
25 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Renderer.ScatterPlot.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Renderer.ScatterPlot');
2 |
3 | Rickshaw.Graph.Renderer.ScatterPlot = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
4 |
5 | name: 'scatterplot',
6 |
7 | defaults: function($super) {
8 |
9 | return Rickshaw.extend( $super(), {
10 | unstack: true,
11 | fill: true,
12 | stroke: false,
13 | padding:{ top: 0.01, right: 0.01, bottom: 0.01, left: 0.01 },
14 | dotSize: 4
15 | } );
16 | },
17 |
18 | initialize: function($super, args) {
19 | $super(args);
20 | },
21 |
22 | render: function() {
23 |
24 | var graph = this.graph;
25 |
26 | graph.vis.selectAll('*').remove();
27 |
28 | graph.series.forEach( function(series) {
29 |
30 | if (series.disabled) return;
31 |
32 | var nodes = graph.vis.selectAll("path")
33 | .data(series.stack.filter( function(d) { return d.y !== null } ))
34 | .enter().append("svg:circle")
35 | .attr("cx", function(d) { return graph.x(d.x) })
36 | .attr("cy", function(d) { return graph.y(d.y) })
37 | .attr("r", function(d) { return ("r" in d) ? d.r : graph.renderer.dotSize});
38 |
39 | Array.prototype.forEach.call(nodes[0], function(n) {
40 | n.setAttribute('fill', series.color);
41 | } );
42 |
43 | }, this );
44 | }
45 | } );
46 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tests/Rickshaw.Class.js:
--------------------------------------------------------------------------------
1 | var Rickshaw = require('../rickshaw');
2 |
3 | exports.load = function(test) {
4 |
5 | test.equal(typeof Rickshaw.Class, 'object', 'Rickshaw.Class is a function');
6 | test.done();
7 | };
8 |
9 | exports.instantiation = function(test) {
10 |
11 | Rickshaw.namespace('Rickshaw.Sample.Class');
12 |
13 | Rickshaw.Sample.Class = Rickshaw.Class.create({
14 | name: 'sample',
15 | concat: function(suffix) {
16 | return [this.name, suffix].join(' ');
17 | }
18 | });
19 |
20 | var sample = new Rickshaw.Sample.Class();
21 | test.equal(sample.concat('polka'), 'sample polka');
22 |
23 | Rickshaw.namespace('Rickshaw.Sample.Class.Prefix');
24 |
25 | Rickshaw.Sample.Subclass = Rickshaw.Class.create( Rickshaw.Sample.Class, {
26 | name: 'sampler',
27 | });
28 |
29 | var sampler = new Rickshaw.Sample.Subclass();
30 | test.equal(sampler.concat('polka'), 'sampler polka');
31 |
32 | test.done();
33 | };
34 |
35 | exports.array = function(test) {
36 |
37 | Rickshaw.namespace('Rickshaw.Sample.Array');
38 |
39 | Rickshaw.Sample.Array = Rickshaw.Class.create(Array, {
40 | second: function() {
41 | return this[1];
42 | }
43 | });
44 |
45 | var array = new Rickshaw.Sample.Array();
46 | array.push('red');
47 | array.push('blue');
48 |
49 | test.equal(array.second(), 'blue');
50 |
51 | test.done();
52 | };
53 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/inconsistent.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
47 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/jsonp.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/gaps.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
47 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/y_axis.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
22 |
23 |
27 |
28 |
61 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.RangeSlider.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.RangeSlider');
2 |
3 | Rickshaw.Graph.RangeSlider = function(args) {
4 |
5 | var element = this.element = args.element;
6 | var graph = this.graph = args.graph;
7 |
8 | $( function() {
9 | $(element).slider( {
10 |
11 | range: true,
12 | min: graph.dataDomain()[0],
13 | max: graph.dataDomain()[1],
14 | values: [
15 | graph.dataDomain()[0],
16 | graph.dataDomain()[1]
17 | ],
18 | slide: function( event, ui ) {
19 |
20 | graph.window.xMin = ui.values[0];
21 | graph.window.xMax = ui.values[1];
22 | graph.update();
23 |
24 | // if we're at an extreme, stick there
25 | if (graph.dataDomain()[0] == ui.values[0]) {
26 | graph.window.xMin = undefined;
27 | }
28 | if (graph.dataDomain()[1] == ui.values[1]) {
29 | graph.window.xMax = undefined;
30 | }
31 | }
32 | } );
33 | } );
34 |
35 | element[0].style.width = graph.width + 'px';
36 |
37 | graph.onUpdate( function() {
38 |
39 | var values = $(element).slider('option', 'values');
40 |
41 | $(element).slider('option', 'min', graph.dataDomain()[0]);
42 | $(element).slider('option', 'max', graph.dataDomain()[1]);
43 |
44 | if (graph.window.xMin == undefined) {
45 | values[0] = graph.dataDomain()[0];
46 | }
47 | if (graph.window.xMax == undefined) {
48 | values[1] = graph.dataDomain()[1];
49 | }
50 |
51 | $(element).slider('option', 'values', values);
52 |
53 | } );
54 | };
55 |
56 |
--------------------------------------------------------------------------------
/html/scripts/d3/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, Michael Bostock
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * The name Michael Bostock may not be used to endorse or promote products
15 | derived from this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##Crimeline
2 |
3 | This project is under heavy development! That means some of this is quite ugly …
4 |
5 | ###Overview
6 |
7 | I plan to create a php/SQL backend to allow live querying against the dataset. To that end, I wrote some php CLI scripts that download the CSV data from the city's website and clean it up, since CSV is easy to directly import into most databases.
8 |
9 | In the meantime, all data is stored as static json. After cleaning the CSV data, I run a second round of scripts to aggregate & output as json.
10 |
11 | ###Getting started
12 |
13 | The code is committed with the necessary .json files already created. If you need to recreate them for any reason:
14 |
15 | 1) Run `clean_calls.php`. This will download and sanitize the call data, outputting to clean_calls.csv It will also output clean_call_types.csv, which is intended for import to SQL as a related table.
16 |
17 | 2) Run `json_calls.php`. This will aggregate the data into the "frames" needed by the mapplayer, outputted as calls.json. Note that the `$framesep` variable at the top should match the `secPerFrame` variable in html/scripts/main.js.
18 |
19 | 3) Copy calls.json into html/scripts
20 |
21 | ###Other
22 | The incident numbers in the calls data are in a slightly different format from the incident numbers in the incident reports. I originally intended to link the calls to incident reports but I haven't finished the code to munge the incident numbers so they match across data sets.
23 |
24 | You'll find the beginning of this code in clean_incidents.php
25 |
26 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_04.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
23 |
24 |
28 |
29 |
52 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Smoother.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Smoother');
2 |
3 | Rickshaw.Graph.Smoother = function(args) {
4 |
5 | this.graph = args.graph;
6 | this.element = args.element;
7 |
8 | var self = this;
9 |
10 | this.aggregationScale = 1;
11 |
12 | if (this.element) {
13 |
14 | $( function() {
15 | $(self.element).slider( {
16 | min: 1,
17 | max: 100,
18 | slide: function( event, ui ) {
19 | self.setScale(ui.value);
20 | self.graph.update();
21 | }
22 | } );
23 | } );
24 | }
25 |
26 | self.graph.stackData.hooks.data.push( {
27 | name: 'smoother',
28 | orderPosition: 50,
29 | f: function(data) {
30 |
31 | if (self.aggregationScale == 1) return data;
32 |
33 | var aggregatedData = [];
34 |
35 | data.forEach( function(seriesData) {
36 |
37 | var aggregatedSeriesData = [];
38 |
39 | while (seriesData.length) {
40 |
41 | var avgX = 0, avgY = 0;
42 | var slice = seriesData.splice(0, self.aggregationScale);
43 |
44 | slice.forEach( function(d) {
45 | avgX += d.x / slice.length;
46 | avgY += d.y / slice.length;
47 | } );
48 |
49 | aggregatedSeriesData.push( { x: avgX, y: avgY } );
50 | }
51 |
52 | aggregatedData.push(aggregatedSeriesData);
53 | } );
54 |
55 | return aggregatedData;
56 | }
57 | } );
58 |
59 | this.setScale = function(scale) {
60 |
61 | if (scale < 1) {
62 | throw "scale out of range: " + scale;
63 | }
64 |
65 | this.aggregationScale = scale;
66 | this.graph.update();
67 | }
68 | };
69 |
70 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Legend.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Legend');
2 |
3 | Rickshaw.Graph.Legend = function(args) {
4 |
5 | var element = this.element = args.element;
6 | var graph = this.graph = args.graph;
7 |
8 | var self = this;
9 |
10 | element.classList.add('rickshaw_legend');
11 |
12 | var list = this.list = document.createElement('ul');
13 | element.appendChild(list);
14 |
15 | var series = graph.series
16 | .map( function(s) { return s } )
17 |
18 | if (!args.naturalOrder) {
19 | series = series.reverse();
20 | }
21 |
22 | this.lines = [];
23 |
24 | this.addLine = function (series) {
25 | var line = document.createElement('li');
26 | line.className = 'line';
27 |
28 | var swatch = document.createElement('div');
29 | swatch.className = 'swatch';
30 | swatch.style.backgroundColor = series.color;
31 |
32 | line.appendChild(swatch);
33 |
34 | var label = document.createElement('span');
35 | label.className = 'label';
36 | label.innerHTML = series.name;
37 |
38 | line.appendChild(label);
39 | list.appendChild(line);
40 |
41 | line.series = series;
42 |
43 | if (series.noLegend) {
44 | line.style.display = 'none';
45 | }
46 |
47 | var _line = { element: line, series: series };
48 | if (self.shelving) {
49 | self.shelving.addAnchor(_line);
50 | self.shelving.updateBehaviour();
51 | }
52 | if (self.highlighter) {
53 | self.highlighter.addHighlightEvents(_line);
54 | }
55 | self.lines.push(_line);
56 | };
57 |
58 | series.forEach( function(s) {
59 | self.addLine(s);
60 | } );
61 |
62 | graph.onUpdate( function() {} );
63 | };
64 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 780px;
3 | margin: auto;
4 | font-family: Arial, Helvetica, sans-serif;
5 | font-size: 13px;
6 | color: #282828;
7 | line-height: 135%;
8 | }
9 | a {
10 | text-decoration: none;
11 | color: steelblue;
12 | }
13 | a:hover {
14 | color: lightblue;
15 | }
16 | h1 {
17 | margin: 1em 0 1em 0;
18 | font-weight: normal;
19 | }
20 | h2 {
21 | font-weight: normal;
22 | margin: 1.4em 0 1em 0;
23 | color: black;
24 | }
25 | .tutorial-chart {
26 | margin-left: 1%;
27 | vertical-align: top;
28 | margin-top: 1em;
29 | }
30 | code {
31 | background-color: #f0f0f0;
32 | padding: 2px;
33 | }
34 | section.example {
35 | border: 1px solid #e4e4e4;
36 | }
37 |
38 | pre.prettyprint {
39 | border: none;
40 | border-top: 1px solid #e8e8e8;
41 | background: #f0f0f0;
42 | padding: 14px 14px;
43 | margin: 0;
44 | white-space: pre-wrap;
45 | }
46 | section iframe {
47 | width: 580px;
48 | height: 270px;
49 | border: none;
50 | margin: 0 auto 12px auto;
51 | display: block;
52 | }
53 | section header {
54 | border-bottom: 1px solid #e8e8e8;
55 | color: #b0b0b0;
56 | margin: 0 0 16px 0;
57 | }
58 | section header a:hover {
59 | color: steelblue;
60 | }
61 | section header a {
62 | color: #d0d0d0;
63 | text-decoration: none;
64 | margin: 6px 10px 0 0;
65 | }
66 | section header h3 {
67 | font-weight: normal;
68 | margin: 0 0 10px 0;
69 | position: relative;
70 | padding: 6px 0 0 8px;
71 | pointer-events: none;
72 | }
73 | section header a {
74 | float: right;
75 | }
76 | .linenums {
77 | color: #d0d0d0;
78 | }
79 | #example_06 iframe,
80 | #example_07 iframe {
81 | width: 750px;
82 | }
83 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/css/legend.css:
--------------------------------------------------------------------------------
1 | .rickshaw_legend {
2 | font-family: Arial;
3 | font-size: 12px;
4 | color: white;
5 | background: #404040;
6 | display: inline-block;
7 | padding: 12px 5px;
8 | border-radius: 2px;
9 | position: relative;
10 | }
11 | .rickshaw_legend:hover {
12 | z-index: 10;
13 | }
14 | .rickshaw_legend .swatch {
15 | width: 10px;
16 | height: 10px;
17 | border: 1px solid rgba(0, 0, 0, 0.2);
18 | }
19 | .rickshaw_legend .line {
20 | clear: both;
21 | line-height: 140%;
22 | padding-right: 15px;
23 | }
24 | .rickshaw_legend .line .swatch {
25 | display: inline-block;
26 | margin-right: 3px;
27 | border-radius: 2px;
28 | }
29 | .rickshaw_legend .label {
30 | margin: 0;
31 | white-space: nowrap;
32 | display: inline;
33 | font-size: inherit;
34 | background-color: transparent;
35 | color: inherit;
36 | font-weight: normal;
37 | line-height: normal;
38 | padding: 0px;
39 | text-shadow: none;
40 | }
41 | .rickshaw_legend .action:hover {
42 | opacity: 0.6;
43 | }
44 | .rickshaw_legend .action {
45 | margin-right: 0.2em;
46 | font-size: 10px;
47 | opacity: 0.2;
48 | cursor: pointer;
49 | font-size: 14px;
50 | }
51 | .rickshaw_legend .line.disabled {
52 | opacity: 0.4;
53 | }
54 | .rickshaw_legend ul {
55 | list-style-type: none;
56 | margin: 0;
57 | padding: 0;
58 | margin: 2px;
59 | cursor: pointer;
60 | }
61 | .rickshaw_legend li {
62 | padding: 0 0 0 2px;
63 | min-width: 80px;
64 | white-space: nowrap;
65 | }
66 | .rickshaw_legend li:hover {
67 | background: rgba(255, 255, 255, 0.08);
68 | border-radius: 3px;
69 | }
70 | .rickshaw_legend li:active {
71 | background: rgba(255, 255, 255, 0.2);
72 | border-radius: 3px;
73 | }
74 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Color.Palette.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace("Rickshaw.Color.Palette");
2 |
3 | Rickshaw.Color.Palette = function(args) {
4 |
5 | var color = new Rickshaw.Fixtures.Color();
6 |
7 | args = args || {};
8 | this.schemes = {};
9 |
10 | this.scheme = color.schemes[args.scheme] || args.scheme || color.schemes.colorwheel;
11 | this.runningIndex = 0;
12 | this.generatorIndex = 0;
13 |
14 | if (args.interpolatedStopCount) {
15 | var schemeCount = this.scheme.length - 1;
16 | var i, j, scheme = [];
17 | for (i = 0; i < schemeCount; i++) {
18 | scheme.push(this.scheme[i]);
19 | var generator = d3.interpolateHsl(this.scheme[i], this.scheme[i + 1]);
20 | for (j = 1; j < args.interpolatedStopCount; j++) {
21 | scheme.push(generator((1 / args.interpolatedStopCount) * j));
22 | }
23 | }
24 | scheme.push(this.scheme[this.scheme.length - 1]);
25 | this.scheme = scheme;
26 | }
27 | this.rotateCount = this.scheme.length;
28 |
29 | this.color = function(key) {
30 | return this.scheme[key] || this.scheme[this.runningIndex++] || this.interpolateColor() || '#808080';
31 | };
32 |
33 | this.interpolateColor = function() {
34 | if (!Array.isArray(this.scheme)) return;
35 | var color;
36 | if (this.generatorIndex == this.rotateCount * 2 - 1) {
37 | color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[0])(0.5);
38 | this.generatorIndex = 0;
39 | this.rotateCount *= 2;
40 | } else {
41 | color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[this.generatorIndex + 1])(0.5);
42 | this.generatorIndex++;
43 | }
44 | this.scheme.push(color);
45 | return color;
46 | };
47 |
48 | };
49 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/status.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
58 |
59 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Ajax.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Ajax');
2 |
3 | Rickshaw.Graph.Ajax = Rickshaw.Class.create( {
4 |
5 | initialize: function(args) {
6 |
7 | this.dataURL = args.dataURL;
8 |
9 | this.onData = args.onData || function(d) { return d };
10 | this.onComplete = args.onComplete || function() {};
11 | this.onError = args.onError || function() {};
12 |
13 | this.args = args; // pass through to Rickshaw.Graph
14 |
15 | this.request();
16 | },
17 |
18 | request: function() {
19 |
20 | $.ajax( {
21 | url: this.dataURL,
22 | dataType: 'json',
23 | success: this.success.bind(this),
24 | error: this.error.bind(this)
25 | } );
26 | },
27 |
28 | error: function() {
29 |
30 | console.log("error loading dataURL: " + this.dataURL);
31 | this.onError(this);
32 | },
33 |
34 | success: function(data, status) {
35 |
36 | data = this.onData(data);
37 | this.args.series = this._splice({ data: data, series: this.args.series });
38 |
39 | this.graph = this.graph || new Rickshaw.Graph(this.args);
40 | this.graph.render();
41 |
42 | this.onComplete(this);
43 | },
44 |
45 | _splice: function(args) {
46 |
47 | var data = args.data;
48 | var series = args.series;
49 |
50 | if (!args.series) return data;
51 |
52 | series.forEach( function(s) {
53 |
54 | var seriesKey = s.key || s.name;
55 | if (!seriesKey) throw "series needs a key or a name";
56 |
57 | data.forEach( function(d) {
58 |
59 | var dataKey = d.key || d.name;
60 | if (!dataKey) throw "data needs a key or a name";
61 |
62 | if (seriesKey == dataKey) {
63 | var properties = ['color', 'name', 'data'];
64 | properties.forEach( function(p) {
65 | if (d[p]) s[p] = d[p];
66 | } );
67 | }
68 | } );
69 | } );
70 |
71 | return series;
72 | }
73 | } );
74 |
75 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/colors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
27 |
28 |
29 |
30 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/css/detail.css:
--------------------------------------------------------------------------------
1 | .rickshaw_graph .detail {
2 | pointer-events: none;
3 | position: absolute;
4 | top: 0;
5 | z-index: 2;
6 | background: rgba(0, 0, 0, 0.1);
7 | bottom: 0;
8 | width: 1px;
9 | transition: opacity 0.25s linear;
10 | -moz-transition: opacity 0.25s linear;
11 | -o-transition: opacity 0.25s linear;
12 | -webkit-transition: opacity 0.25s linear;
13 | }
14 | .rickshaw_graph .detail.inactive {
15 | opacity: 0;
16 | }
17 | .rickshaw_graph .detail .item.active {
18 | opacity: 1;
19 | }
20 | .rickshaw_graph .detail .x_label {
21 | font-family: Arial, sans-serif;
22 | border-radius: 3px;
23 | padding: 6px;
24 | opacity: 0.5;
25 | border: 1px solid #e0e0e0;
26 | font-size: 12px;
27 | position: absolute;
28 | background: white;
29 | white-space: nowrap;
30 | }
31 | .rickshaw_graph .detail .item {
32 | position: absolute;
33 | z-index: 2;
34 | border-radius: 3px;
35 | padding: 0.25em;
36 | font-size: 12px;
37 | font-family: Arial, sans-serif;
38 | opacity: 0;
39 | background: rgba(0, 0, 0, 0.4);
40 | color: white;
41 | border: 1px solid rgba(0, 0, 0, 0.4);
42 | margin-left: 1em;
43 | margin-top: -1em;
44 | white-space: nowrap;
45 | }
46 | .rickshaw_graph .detail .item.active {
47 | opacity: 1;
48 | background: rgba(0, 0, 0, 0.8);
49 | }
50 | .rickshaw_graph .detail .item:before {
51 | content: "\25c2";
52 | position: absolute;
53 | left: -0.5em;
54 | color: rgba(0, 0, 0, 0.7);
55 | width: 0;
56 | }
57 | .rickshaw_graph .detail .dot {
58 | width: 4px;
59 | height: 4px;
60 | margin-left: -4px;
61 | margin-top: -3px;
62 | border-radius: 5px;
63 | position: absolute;
64 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
65 | background: white;
66 | border-width: 2px;
67 | border-style: solid;
68 | display: none;
69 | background-clip: padding-box;
70 | }
71 | .rickshaw_graph .detail .dot.active {
72 | display: block;
73 | }
74 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tests/Rickshaw.Series.FixedDuration.js:
--------------------------------------------------------------------------------
1 | var Rickshaw = require("../rickshaw");
2 |
3 | function seriesData() {
4 | return {
5 | name: 'series1',
6 | data: [ {x: 0, y: 20}, {x: 1, y: 21}, { x: 2, y: 15} ],
7 | color: 'red'
8 | };
9 | }
10 |
11 | exports.basic = function(test) {
12 |
13 | test.equal(typeof Rickshaw.Series.FixedDuration, 'function', 'Rickshaw.Series.FixedDuration is a function');
14 | test.done();
15 | };
16 |
17 | exports.initialize = function(test) {
18 |
19 | function instantiateMalformed() {
20 |
21 | var series = new Rickshaw.Series.FixedDuration(
22 | [seriesData()],
23 | 'spectrum2001',
24 | { timeBase: 0, maxDataPoints: 2000 }
25 | );
26 | }
27 |
28 | test.throws(instantiateMalformed, 'FixedDuration series requires timeInterval', 'we die without a timeInterval');
29 |
30 | function instantiateMalformed() {
31 |
32 | var series = new Rickshaw.Series.FixedDuration(
33 | [seriesData()],
34 | 'spectrum2001',
35 | { timeBase: 0, timeInterval: 30 }
36 | );
37 | }
38 |
39 | test.throws(instantiateMalformed, 'FixedDuration series requires maxDataPoints', 'we die without maxDataPoints');
40 |
41 | var series = new Rickshaw.Series.FixedDuration(
42 | [seriesData()],
43 | 'spectrum2001',
44 | {
45 | timeBase: 0,
46 | timeInterval: 30,
47 | maxDataPoints: 2000
48 | }
49 | );
50 |
51 | test.ok(series instanceof Rickshaw.Series.FixedDuration);
52 | test.ok(series instanceof Array);
53 | test.done();
54 | }
55 |
56 | exports.addData = function(test) {
57 |
58 | var series = new Rickshaw.Series.FixedDuration(
59 | [seriesData()],
60 | 'spectrum2001',
61 | {
62 | timeBase: 0,
63 | timeInterval: 1,
64 | maxDataPoints: 20
65 | }
66 | );
67 |
68 | for (var i = 0; i < 300; i++) {
69 | series.addData({series1: 42});
70 | }
71 |
72 | test.equal(series[0].data.length, 20 + 2, 'series length stuck around maxDataPoints');
73 | test.equal(series.currentSize, 20, 'series.currentSize is stuck at maxDataPoints');
74 | test.done();
75 | }
76 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/stops.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
40 |
41 |
42 |
43 |
47 |
48 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tests/Rickshaw.Graph.Renderer.js:
--------------------------------------------------------------------------------
1 | var Rickshaw = require("../rickshaw");
2 |
3 | exports.domain = function(test) {
4 |
5 | // document comes from jsdom
6 | var el = document.createElement("div");
7 |
8 | var graph = new Rickshaw.Graph({
9 | element: el,
10 | width: 960,
11 | height: 500,
12 | padding: { top: 0, right: 0, bottom: 0, left: 0 },
13 | renderer: 'scatterplot',
14 | series: [
15 | {
16 | color: 'steelblue',
17 | data: [
18 | { x: 0, y: 40 },
19 | { x: 1, y: 49 },
20 | { x: 2, y: 38 },
21 | { x: 3, y: 30 },
22 | { x: 4, y: 32 }
23 | ]
24 | }
25 | ]
26 | });
27 |
28 | var domain = graph.renderer.domain();
29 | test.deepEqual(domain, { x: [ 0, 4 ], y: [ 0, 49 ] }, 'domain matches');
30 |
31 | // with padding
32 |
33 | graph.configure({ padding: { top: 0.1, right: 0.1, bottom: 0.1, left: 0.1 }});
34 |
35 | domain = graph.renderer.domain();
36 | test.deepEqual(domain, { x: [ -0.4, 4.44 ], y: [ 0, 49 + 4.9 ] }, 'domain matches with padding');
37 |
38 | // negative y-values minus auto
39 |
40 | graph.series[0].data[2].y = -72;
41 | graph.configure({ padding: { top: 0, right: 0, bottom: 0, left: 0 }});
42 |
43 | domain = graph.renderer.domain();
44 | test.deepEqual(domain, { x: [ 0, 4 ], y: [ 0, 49 ] }, 'domain matches with negative numbers and no auto');
45 |
46 | // negative y-values w/ auto
47 |
48 | graph.series[0].data[2].y = -72;
49 | graph.configure({ padding: { top: 0, right: 0, bottom: 0, left: 0 }, min: 'auto'});
50 |
51 | domain = graph.renderer.domain();
52 | test.deepEqual(domain, { x: [ 0, 4 ], y: [ -72, 49 ] }, 'domain matches with negative numbers and min auto');
53 |
54 | // different series lengths
55 |
56 | graph.series.push({
57 | color: 'lightblue',
58 | data: [ { x: 1, y: 20 }, { x: 2, y: 38 }, { x: 3, y: 30 }, { x: 4, y: 32 }, { x: 5, y: 32 } ]
59 | });
60 |
61 | graph.stackData();
62 | domain = graph.renderer.domain();
63 | test.deepEqual(domain, { x: [ 0, 5 ], y: [ -72, 49 ] }, 'multiple length series extents match');
64 |
65 | test.done();
66 | };
67 |
68 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Behavior.Series.Highlight.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Highlight');
2 |
3 | Rickshaw.Graph.Behavior.Series.Highlight = function(args) {
4 |
5 | this.graph = args.graph;
6 | this.legend = args.legend;
7 |
8 | var self = this;
9 |
10 | var colorSafe = {};
11 | var activeLine = null;
12 |
13 | this.addHighlightEvents = function (l) {
14 |
15 | l.element.addEventListener( 'mouseover', function(e) {
16 |
17 | if (activeLine) return;
18 | else activeLine = l;
19 |
20 | self.legend.lines.forEach( function(line, index) {
21 |
22 | if (l === line) {
23 |
24 | // if we're not in a stacked renderer bring active line to the top
25 | if (index > 0 && self.graph.renderer.unstack) {
26 |
27 | var seriesIndex = self.graph.series.length - index - 1;
28 | line.originalIndex = seriesIndex;
29 |
30 | var series = self.graph.series.splice(seriesIndex, 1)[0];
31 | self.graph.series.push(series);
32 | }
33 | return;
34 | }
35 |
36 | colorSafe[line.series.name] = colorSafe[line.series.name] || line.series.color;
37 | line.series.color = d3.interpolateRgb(line.series.color, d3.rgb('#d8d8d8'))(0.8).toString();
38 | } );
39 |
40 | self.graph.update();
41 |
42 | }, false );
43 |
44 | l.element.addEventListener( 'mouseout', function(e) {
45 |
46 | if (!activeLine) return;
47 | else activeLine = null;
48 |
49 | self.legend.lines.forEach( function(line) {
50 |
51 | // return reordered series to its original place
52 | if (l === line && line.hasOwnProperty('originalIndex')) {
53 |
54 | var series = self.graph.series.pop();
55 | self.graph.series.splice(line.originalIndex, 0, series);
56 | delete line['originalIndex'];
57 | }
58 |
59 | if (colorSafe[line.series.name]) {
60 | line.series.color = colorSafe[line.series.name];
61 | }
62 | } );
63 |
64 | self.graph.update();
65 |
66 | }, false );
67 | };
68 |
69 | if (this.legend) {
70 | this.legend.lines.forEach( function(l) {
71 | self.addHighlightEvents(l);
72 | } );
73 | }
74 |
75 | };
76 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/Makefile:
--------------------------------------------------------------------------------
1 | NODE_PREFIX=$(shell npm prefix)
2 | NODE_MODULES=$(NODE_PREFIX)/node_modules
3 |
4 | CSS_MIN=$(NODE_MODULES)/.bin/cleancss
5 | JS_MIN=$(NODE_MODULES)/.bin/uglifyjs
6 |
7 | CSS_FILES=\
8 | src/css/detail.css\
9 | src/css/graph.css\
10 | src/css/legend.css\
11 |
12 | JS_FILES=\
13 | src/js/Rickshaw.js\
14 | src/js/Rickshaw.Class.js\
15 | src/js/Rickshaw.Compat.ClassList.js\
16 | src/js/Rickshaw.Graph.js\
17 | src/js/Rickshaw.Fixtures.Color.js\
18 | src/js/Rickshaw.Fixtures.RandomData.js\
19 | src/js/Rickshaw.Fixtures.Time.js\
20 | src/js/Rickshaw.Fixtures.Number.js\
21 | src/js/Rickshaw.Color.Palette.js\
22 | src/js/Rickshaw.Graph.Ajax.js\
23 | src/js/Rickshaw.Graph.Annotate.js\
24 | src/js/Rickshaw.Graph.Axis.Time.js\
25 | src/js/Rickshaw.Graph.Axis.Y.js\
26 | src/js/Rickshaw.Graph.Behavior.Series.Highlight.js\
27 | src/js/Rickshaw.Graph.Behavior.Series.Order.js\
28 | src/js/Rickshaw.Graph.Behavior.Series.Toggle.js\
29 | src/js/Rickshaw.Graph.HoverDetail.js\
30 | src/js/Rickshaw.Graph.JSONP.js\
31 | src/js/Rickshaw.Graph.Legend.js\
32 | src/js/Rickshaw.Graph.RangeSlider.js\
33 | src/js/Rickshaw.Graph.Renderer.js\
34 | src/js/Rickshaw.Graph.Renderer.Line.js\
35 | src/js/Rickshaw.Graph.Renderer.Stack.js\
36 | src/js/Rickshaw.Graph.Renderer.Bar.js\
37 | src/js/Rickshaw.Graph.Renderer.Area.js\
38 | src/js/Rickshaw.Graph.Renderer.ScatterPlot.js\
39 | src/js/Rickshaw.Graph.Smoother.js\
40 | src/js/Rickshaw.Graph.Unstacker.js\
41 | src/js/Rickshaw.Series.js\
42 | src/js/Rickshaw.Series.FixedDuration.js\
43 |
44 | .PHONY: clean build
45 |
46 | build: rickshaw.min.css rickshaw.min.js
47 |
48 | clean:
49 | rm -rf rickshaw.css rickshaw.js rickshaw.min.*
50 |
51 | $(CSS_MIN):
52 | npm install clean-css
53 |
54 | $(JS_MIN):
55 | npm install uglify-js
56 |
57 | rickshaw.css:
58 | cat $(CSS_FILES) > rickshaw.css
59 |
60 | rickshaw.js:
61 | cat $(JS_FILES) > rickshaw.js
62 |
63 | rickshaw.min.css: $(CSS_MIN) rickshaw.css
64 | $(CSS_MIN) rickshaw.css > rickshaw.min.css
65 |
66 | rickshaw.min.js: $(JS_MIN) rickshaw.js
67 | $(JS_MIN) --reserved-names "\$$super" rickshaw.js > rickshaw.min.js
68 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/lines.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
26 |
27 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Axis.Time.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Axis.Time');
2 |
3 | Rickshaw.Graph.Axis.Time = function(args) {
4 |
5 | var self = this;
6 |
7 | this.graph = args.graph;
8 | this.elements = [];
9 | this.ticksTreatment = args.ticksTreatment || 'plain';
10 | this.fixedTimeUnit = args.timeUnit;
11 |
12 | var time = new Rickshaw.Fixtures.Time();
13 |
14 | this.appropriateTimeUnit = function() {
15 |
16 | var unit;
17 | var units = time.units;
18 |
19 | var domain = this.graph.x.domain();
20 | var rangeSeconds = domain[1] - domain[0];
21 |
22 | units.forEach( function(u) {
23 | if (Math.floor(rangeSeconds / u.seconds) >= 2) {
24 | unit = unit || u;
25 | }
26 | } );
27 |
28 | return (unit || time.units[time.units.length - 1]);
29 | };
30 |
31 | this.tickOffsets = function() {
32 |
33 | var domain = this.graph.x.domain();
34 |
35 | var unit = this.fixedTimeUnit || this.appropriateTimeUnit();
36 | var count = Math.ceil((domain[1] - domain[0]) / unit.seconds);
37 |
38 | var runningTick = domain[0];
39 |
40 | var offsets = [];
41 |
42 | for (var i = 0; i < count; i++) {
43 |
44 | var tickValue = time.ceil(runningTick, unit);
45 | runningTick = tickValue + unit.seconds / 2;
46 |
47 | offsets.push( { value: tickValue, unit: unit } );
48 | }
49 |
50 | return offsets;
51 | };
52 |
53 | this.render = function() {
54 |
55 | this.elements.forEach( function(e) {
56 | e.parentNode.removeChild(e);
57 | } );
58 |
59 | this.elements = [];
60 |
61 | var offsets = this.tickOffsets();
62 |
63 | offsets.forEach( function(o) {
64 |
65 | if (self.graph.x(o.value) > self.graph.x.range()[1]) return;
66 |
67 | var element = document.createElement('div');
68 | element.style.left = self.graph.x(o.value) + 'px';
69 | element.classList.add('x_tick');
70 | element.classList.add(self.ticksTreatment);
71 |
72 | var title = document.createElement('div');
73 | title.classList.add('title');
74 | title.innerHTML = o.unit.formatter(new Date(o.value * 1000));
75 | element.appendChild(title);
76 |
77 | self.graph.element.appendChild(element);
78 | self.elements.push(element);
79 |
80 | } );
81 | };
82 |
83 | this.graph.onUpdate( function() { self.render() } );
84 | };
85 |
86 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Series.FixedDuration.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Series.FixedDuration');
2 |
3 | Rickshaw.Series.FixedDuration = Rickshaw.Class.create(Rickshaw.Series, {
4 |
5 | initialize: function (data, palette, options) {
6 |
7 | var options = options || {}
8 |
9 | if (typeof(options.timeInterval) === 'undefined') {
10 | throw new Error('FixedDuration series requires timeInterval');
11 | }
12 |
13 | if (typeof(options.maxDataPoints) === 'undefined') {
14 | throw new Error('FixedDuration series requires maxDataPoints');
15 | }
16 |
17 | this.palette = new Rickshaw.Color.Palette(palette);
18 | this.timeBase = typeof(options.timeBase) === 'undefined' ? Math.floor(new Date().getTime() / 1000) : options.timeBase;
19 | this.setTimeInterval(options.timeInterval);
20 |
21 | if (this[0] && this[0].data && this[0].data.length) {
22 | this.currentSize = this[0].data.length;
23 | this.currentIndex = this[0].data.length;
24 | } else {
25 | this.currentSize = 0;
26 | this.currentIndex = 0;
27 | }
28 |
29 | this.maxDataPoints = options.maxDataPoints;
30 |
31 |
32 | if (data && (typeof(data) == "object") && (data instanceof Array)) {
33 | data.forEach( function (item) { this.addItem(item) }, this );
34 | this.currentSize += 1;
35 | this.currentIndex += 1;
36 | }
37 |
38 | // reset timeBase for zero-filled values if needed
39 | this.timeBase -= (this.maxDataPoints - this.currentSize) * this.timeInterval;
40 |
41 | // zero-fill up to maxDataPoints size if we don't have that much data yet
42 | if ((typeof(this.maxDataPoints) !== 'undefined') && (this.currentSize < this.maxDataPoints)) {
43 | for (var i = this.maxDataPoints - this.currentSize - 1; i > 0; i--) {
44 | this.currentSize += 1;
45 | this.currentIndex += 1;
46 | this.forEach( function (item) {
47 | item.data.unshift({ x: ((i-1) * this.timeInterval || 1) + this.timeBase, y: 0, i: i });
48 | }, this );
49 | }
50 | }
51 | },
52 |
53 | addData: function($super, data) {
54 |
55 | $super(data)
56 |
57 | this.currentSize += 1;
58 | this.currentIndex += 1;
59 |
60 | if (this.maxDataPoints !== undefined) {
61 | while (this.currentSize > this.maxDataPoints) {
62 | this.dropData();
63 | }
64 | }
65 | },
66 |
67 | dropData: function() {
68 |
69 | this.forEach(function(item) {
70 | item.data.splice(0, 1);
71 | } );
72 |
73 | this.currentSize -= 1;
74 | },
75 |
76 | getIndex: function () {
77 | return this.currentIndex;
78 | }
79 | } );
80 |
81 |
--------------------------------------------------------------------------------
/html/scripts/jquery-tod.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | /*
3 | note: 'this' in the jquery plugin context refers to the dom node we were invoked on.
4 | For that reason, you should return 'this' to maintain chainability.
5 |
6 | XXX TODO BUG ETC: This is ultra Q&D! I intend to flesh this out into a real plugin
7 | after this project. Much thanks to http://wesnoth.org/ for hours of fun and for
8 | lending me these images. Everything here is GPLv3!
9 | */
10 | var methods = {
11 | init: function(options) {
12 | return this.each(function() {
13 | var $this = $(this),
14 | data = $(this).data('tod');
15 |
16 | if (options !== undefined && options['date']) {
17 | //console.log("tod init with " + options['date']);
18 | var oDate = new Date(options['date']);
19 | } else {
20 | //console.log("tod init with now()");
21 | var oDate = new Date();
22 | }
23 |
24 | var img = oDate.getHours();
25 | //console.log("tod hours is " + img);
26 | img = "images/tod/" + img + ".png";
27 |
28 | if (! data) {
29 | //init tod on a new dom element
30 | //console.log("not data");
31 | $(this).data('tod', {
32 | tod_set: true,
33 | options: options,
34 | img: img
35 | });
36 | $(this).html(" ");
37 | } else if (data.img != img) {
38 | //XXX why am I doing this with data instead of attr?
39 | //console.log("!= img");
40 | data.img = img;
41 | $(this).data('tod', data);
42 | $("#jquery-tod-img").attr("src", img)
43 | }
44 |
45 | });
46 | },
47 | setTime: function(newTime) { //XXX do not use! blah data.tod.blah
48 | console.log("setTime here: " + newTime);
49 | return this.each(function() {
50 | var data = $(this).data('tod');
51 | if (! data || data.tod === undefined) {
52 | //XXX should do more here
53 | //$.error("tod.setTime() on a non-tod object!");
54 | }
55 |
56 | var oDate = new Date(newTime);
57 | var img = oDate.getHours();
58 | img = "images/tod/" + img + ".png";
59 | $(this).html(" ");
60 | });
61 | }
62 | };
63 |
64 | $.fn.tod = function(method) {
65 | if (methods[method]) {
66 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
67 | } else if (typeof method === 'object' || ! method) {
68 | return methods.init.apply(this, arguments);
69 | } else {
70 | $.error('Method ' + method + ' does not exist on tod.');
71 | }
72 | };
73 | })(jQuery);
74 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/formatter.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
33 |
34 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Renderer.Area.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Renderer.Area');
2 |
3 | Rickshaw.Graph.Renderer.Area = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
4 |
5 | name: 'area',
6 |
7 | defaults: function($super) {
8 |
9 | return Rickshaw.extend( $super(), {
10 | unstack: false,
11 | fill: false,
12 | stroke: false
13 | } );
14 | },
15 |
16 | seriesPathFactory: function() {
17 |
18 | var graph = this.graph;
19 |
20 | var factory = d3.svg.area()
21 | .x( function(d) { return graph.x(d.x) } )
22 | .y0( function(d) { return graph.y(d.y0) } )
23 | .y1( function(d) { return graph.y(d.y + d.y0) } )
24 | .interpolate(graph.interpolation).tension(this.tension)
25 |
26 | factory.defined && factory.defined( function(d) { return d.y !== null } );
27 | return factory;
28 | },
29 |
30 | seriesStrokeFactory: function() {
31 |
32 | var graph = this.graph;
33 |
34 | var factory = d3.svg.line()
35 | .x( function(d) { return graph.x(d.x) } )
36 | .y( function(d) { return graph.y(d.y + d.y0) } )
37 | .interpolate(graph.interpolation).tension(this.tension)
38 |
39 | factory.defined && factory.defined( function(d) { return d.y !== null } );
40 | return factory;
41 | },
42 |
43 | render: function() {
44 |
45 | var graph = this.graph;
46 |
47 | graph.vis.selectAll('*').remove();
48 |
49 | // insert or stacked areas so strokes lay on top of areas
50 | var method = this.unstack ? 'append' : 'insert';
51 |
52 | var nodes = graph.vis.selectAll("path")
53 | .data(this.graph.stackedData)
54 | .enter()[method]("svg:g", 'g');
55 |
56 | nodes.append("svg:path")
57 | .attr("d", this.seriesPathFactory())
58 | .attr("class", 'area');
59 |
60 | if (this.stroke) {
61 | nodes.append("svg:path")
62 | .attr("d", this.seriesStrokeFactory())
63 | .attr("class", 'line');
64 | }
65 |
66 | var i = 0;
67 | graph.series.forEach( function(series) {
68 | if (series.disabled) return;
69 | series.path = nodes[0][i++];
70 | this._styleSeries(series);
71 | }, this );
72 | },
73 |
74 | _styleSeries: function(series) {
75 |
76 | if (!series.path) return;
77 |
78 | d3.select(series.path).select('.area')
79 | .attr('fill', series.color);
80 |
81 | if (this.stroke) {
82 | d3.select(series.path).select('.line')
83 | .attr('fill', 'none')
84 | .attr('stroke', series.stroke || d3.interpolateRgb(series.color, 'black')(0.125))
85 | .attr('stroke-width', this.strokeWidth);
86 | }
87 |
88 | if (series.className) {
89 | series.path.setAttribute('class', series.className);
90 | }
91 | }
92 | } );
93 |
94 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Axis.Y.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Axis.Y');
2 |
3 | Rickshaw.Graph.Axis.Y = function(args) {
4 |
5 | var self = this;
6 | var berthRate = 0.10;
7 |
8 | this.initialize = function(args) {
9 |
10 | this.graph = args.graph;
11 | this.orientation = args.orientation || 'right';
12 |
13 | var pixelsPerTick = args.pixelsPerTick || 75;
14 | this.ticks = args.ticks || Math.floor(this.graph.height / pixelsPerTick);
15 | this.tickSize = args.tickSize || 4;
16 | this.ticksTreatment = args.ticksTreatment || 'plain';
17 |
18 | if (args.element) {
19 |
20 | this.element = args.element;
21 | this.vis = d3.select(args.element)
22 | .append("svg:svg")
23 | .attr('class', 'rickshaw_graph y_axis');
24 |
25 | this.element = this.vis[0][0];
26 | this.element.style.position = 'relative';
27 |
28 | this.setSize({ width: args.width, height: args.height });
29 |
30 | } else {
31 | this.vis = this.graph.vis;
32 | }
33 |
34 | this.graph.onUpdate( function() { self.render() } );
35 | };
36 |
37 | this.setSize = function(args) {
38 |
39 | args = args || {};
40 |
41 | if (!this.element) return;
42 |
43 | if (typeof window !== 'undefined') {
44 |
45 | var style = window.getComputedStyle(this.element.parentNode, null);
46 | var elementWidth = parseInt(style.getPropertyValue('width'));
47 |
48 | if (!args.auto) {
49 | var elementHeight = parseInt(style.getPropertyValue('height'));
50 | }
51 | }
52 |
53 | this.width = args.width || elementWidth || this.graph.width * berthRate;
54 | this.height = args.height || elementHeight || this.graph.height;
55 |
56 | this.vis
57 | .attr('width', this.width)
58 | .attr('height', this.height * (1 + berthRate));
59 |
60 | var berth = this.height * berthRate;
61 | this.element.style.top = -1 * berth + 'px';
62 | };
63 |
64 | this.render = function() {
65 |
66 | if (this.graph.height !== this._renderHeight) this.setSize({ auto: true });
67 |
68 | var axis = d3.svg.axis().scale(this.graph.y).orient(this.orientation);
69 | axis.tickFormat( args.tickFormat || function(y) { return y } );
70 |
71 | if (this.orientation == 'left') {
72 | var berth = this.height * berthRate;
73 | var transform = 'translate(' + this.width + ', ' + berth + ')';
74 | }
75 |
76 | if (this.element) {
77 | this.vis.selectAll('*').remove();
78 | }
79 |
80 | this.vis
81 | .append("svg:g")
82 | .attr("class", ["y_ticks", this.ticksTreatment].join(" "))
83 | .attr("transform", transform)
84 | .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize))
85 |
86 | var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width;
87 |
88 | this.graph.vis
89 | .append("svg:g")
90 | .attr("class", "y_grid")
91 | .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
92 |
93 | this._renderHeight = this.graph.height;
94 | };
95 |
96 | this.initialize(args);
97 | };
98 |
99 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_05.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
27 |
31 |
32 |
75 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/fixed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
40 |
41 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/clean_incidents.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php
2 | $end_ts) {
82 | continue;
83 | }
84 |
85 | $line = array_map('cleanVal', $line);
86 | /*
87 | Array
88 | (
89 | [0] => Incident ID
90 | [1] => Incident Type
91 | [2] => Case Number
92 | [3] => Incident Date
93 | [4] => Suspect
94 | [5] => Arrested
95 | [6] => Address
96 | [7] => Victim
97 | [8] => Details
98 | [9] => Released By
99 | [10] => Date Modified
100 | )
101 | */
102 |
103 | $line[3] = date("Y-m-d H:i:s", $ts);
104 |
105 | $line[2] = "\"{$line[2]}\"";
106 | $line[4] = "\"{$line[4]}\"";
107 | $line[5] = "\"{$line[5]}\"";
108 | $line[6] = "\"{$line[6]}\"";
109 | $line[7] = "\"{$line[7]}\"";
110 | $line[8] = "\"{$line[8]}\"";
111 |
112 | //print_r($line);
113 | fwrite($fp_out, implode(',', $line) . "\n");
114 | $j++;
115 |
116 | echo "\r$i lines, $j in date range ...";
117 | }
118 |
119 | echo " Done!\n";
120 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tests/Rickshaw.Graph.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 |
3 | exports.svg = function(test) {
4 |
5 | var jsdom = require("jsdom").jsdom;
6 | global.document = jsdom("");
7 | global.window = global.document.createWindow();
8 |
9 | var Rickshaw = require('../rickshaw');
10 | new Rickshaw.Compat.ClassList();
11 |
12 | var el = document.createElement("div");
13 |
14 | var graph = new Rickshaw.Graph({
15 | element: el,
16 | width: 960,
17 | height: 500,
18 | renderer: 'scatterplot',
19 | series: [{
20 | color: 'steelblue',
21 | data: [
22 | { x: 0, y: 40 },
23 | { x: 1, y: 49 },
24 | { x: 2, y: 38 },
25 | { x: 3, y: 30 },
26 | { x: 4, y: 32 } ]
27 | }]
28 | } );
29 |
30 | graph.renderer.dotSize = 6;
31 | graph.render();
32 |
33 | var generatedSVG = el.innerHTML;
34 |
35 | var exampleSVGFilename = __dirname + '/data/simple.svg';
36 | var exampleSVG = fs.readFileSync(exampleSVGFilename, 'utf8').trim();
37 |
38 | test.equal(generatedSVG, exampleSVG, "simple graph svg content matches");
39 |
40 | test.done();
41 | }
42 |
43 | exports.inconsistent = function(test) {
44 |
45 | var jsdom = require("jsdom").jsdom;
46 | global.document = jsdom("");
47 | global.window = global.document.createWindow();
48 |
49 | var Rickshaw = require('../rickshaw');
50 | new Rickshaw.Compat.ClassList();
51 |
52 | var el = document.createElement("div");
53 |
54 | var series = [
55 | {
56 | color: 'steelblue',
57 | data: [ { x: 0, y: 40 }, { x: 1, y: 49 }, { x: 2, y: 38 } ],
58 | }, {
59 | color: 'red',
60 | data: [ { x: 0, y: 40 }, { x: 1, y: 49 }, { x: 2, y: 38 } ],
61 | }
62 | ];
63 |
64 | test.doesNotThrow( function() {
65 |
66 | var graph = new Rickshaw.Graph({
67 | element: el,
68 | width: 960,
69 | height: 500,
70 | renderer: 'stack',
71 | series: series
72 | });
73 |
74 | }, "create basic graph okay" );
75 |
76 | series[0].data.push( { x: 3, y: 88 } );
77 |
78 | test.doesNotThrow( function() {
79 |
80 | var graph = new Rickshaw.Graph({
81 | element: el,
82 | width: 960,
83 | height: 500,
84 | renderer: 'line',
85 | series: series
86 | });
87 |
88 | }, "we don't throw for inconsistent length series for lines" );
89 |
90 | test.throws( function() {
91 |
92 | var graph = new Rickshaw.Graph({
93 | element: el,
94 | width: 960,
95 | height: 500,
96 | renderer: 'stack',
97 | series: series
98 | });
99 |
100 | }, null, "throw for inconsistent stacked series for stack renderer" );
101 |
102 | test.throws( function() {
103 |
104 | var graph = new Rickshaw.Graph({
105 | element: null,
106 | width: 960,
107 | height: 500,
108 | renderer: 'stack',
109 | series: series
110 | });
111 |
112 | }, null, "throw an error for undefined element reference" );
113 |
114 | test.done();
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/json_calls.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php
2 | = $framesep) {
77 | //increment frame
78 | $curTime += $framesep;
79 | $framenum++;
80 | while ($curTime + $framesep < $testTime) {
81 | //insert blank frames if necessary
82 | $frames[$framenum]['data'] = array();
83 | $frames[$framenum]['t'] = date("Y/m/d H:i:00", $curTime); //frame title
84 | $curTime += $framesep;
85 | $framenum++;
86 | }
87 | }
88 |
89 | $frames[$framenum]['data'][] = $item;
90 | $frames[$framenum]['t'] = date("Y/m/d H:i:00", $curTime); //frame title
91 | // see http://dygraphs.com/date-formats.html for why Y/m/d
92 |
93 | /*
94 | if ($framenum > 5) {
95 | break;
96 | }
97 | */
98 | echo "\r$i lines, $framenum frames...";
99 | }
100 | $data = array_values($frames);
101 | $json = json_encode($data);
102 | fwrite($fp_out, $json);
103 | echo "\n";
104 |
105 | echo "Done!\n";
106 |
107 |
--------------------------------------------------------------------------------
/html/scripts/mapplayer/frame.js:
--------------------------------------------------------------------------------
1 | function MapFrame(params) {
2 | //Init
3 | var map;
4 | var markers = [];
5 | var iws = []; //info windows
6 | var listeners = [];
7 | var opacity = 0;
8 | var strokeOpacityBase = 0.5;
9 |
10 | for (var i= 0; i < params.data.length; i++) {
11 | map = params.map;
12 | //console.dir(params.data[i]);
13 | var ll = new google.maps.LatLng(params.data[i].lat, params.data[i].lng);
14 | //TODO: abstract the icon and allow it to be set per marker
15 | var mObj = {
16 | position: ll,
17 | icon: {
18 | path: google.maps.SymbolPath.CIRCLE,
19 | scale: 4,
20 | fillColor: "#ff0000",
21 | fillOpacity: opacity,
22 | strokeWeight: 1,
23 | strokeOpacity: strokeOpacityBase * opacity
24 | },
25 | };
26 | if (params.data[i].title) {
27 | mObj.title = params.data[i].title;
28 | }
29 | if (params.data[i].color) {
30 | mObj.icon.fillColor = params.data[i].color;
31 | }
32 | var m = new google.maps.Marker(mObj);
33 | markers[i] = m;
34 | }
35 | setMarkerOpacities();
36 |
37 | if (params.exData != undefined) {
38 | this.exData = params.exData;
39 | }
40 |
41 |
42 | //Private functions
43 |
44 | function showIW(y) {
45 | //console.log("showIW " + y);
46 | //console.dir(markers);
47 | if (iws[y] === undefined) {
48 | var iwObj = {
49 | content: markers[y].title
50 | };
51 | if (params.data[y].iwContent) {
52 | iwObj.content = params.data[y].iwContent;
53 | }
54 | var iw = new google.maps.InfoWindow(iwObj);
55 | iws[y] = iw;
56 | }
57 | iws[y].open(map,markers[y]);
58 | }
59 |
60 | function setMarkerOpacities() {
61 | for (var i= 0; i < markers.length; i++) {
62 | var color = markers[i].icon.fillColor;
63 | var curIcon = markers[i].icon;
64 | curIcon.fillOpacity = opacity;
65 | curIcon.strokeOpacity = strokeOpacityBase * opacity;
66 | markers[i].setIcon(curIcon);
67 | }
68 | }
69 |
70 |
71 | //Public Functions
72 |
73 |
74 | this.draw = function() {
75 | var callback;
76 | if (opacity <= 0) {
77 | return;
78 | }
79 | for (var i= 0; i < markers.length; i++) {
80 | callback = function(i) {
81 | return function () {
82 | showIW(i);
83 | };
84 | }(i);
85 | markers[i].setMap(map);
86 | //google.maps.event.addListener(markers[i], 'click', function() { showIW(i); }); //Y U no work?
87 | listeners[i] = google.maps.event.addListener(markers[i], 'click', callback);
88 | }
89 | }
90 |
91 | this.setOpacity = function(o) {
92 | opacity = o;
93 | if (opacity <= 0) {
94 | opacity = 0;
95 | this.hide();
96 | return;
97 | }
98 | setMarkerOpacities();
99 | }
100 |
101 | this.setRelativeOpacity = function(o) {
102 | this.setOpacity(opacity += o);
103 | }
104 |
105 | this.hide = function() {
106 | for (var i= 0; i < markers.length; i++) {
107 | markers[i].setMap(null)
108 | google.maps.event.removeListener(listeners[i]);
109 | listeners[i] = null;
110 | }
111 | listeners = [];
112 | }
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Fixtures.Color.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Fixtures.Color');
2 |
3 | Rickshaw.Fixtures.Color = function() {
4 |
5 | this.schemes = {};
6 |
7 | this.schemes.spectrum14 = [
8 | '#ecb796',
9 | '#dc8f70',
10 | '#b2a470',
11 | '#92875a',
12 | '#716c49',
13 | '#d2ed82',
14 | '#bbe468',
15 | '#a1d05d',
16 | '#e7cbe6',
17 | '#d8aad6',
18 | '#a888c2',
19 | '#9dc2d3',
20 | '#649eb9',
21 | '#387aa3'
22 | ].reverse();
23 |
24 | this.schemes.spectrum2000 = [
25 | '#57306f',
26 | '#514c76',
27 | '#646583',
28 | '#738394',
29 | '#6b9c7d',
30 | '#84b665',
31 | '#a7ca50',
32 | '#bfe746',
33 | '#e2f528',
34 | '#fff726',
35 | '#ecdd00',
36 | '#d4b11d',
37 | '#de8800',
38 | '#de4800',
39 | '#c91515',
40 | '#9a0000',
41 | '#7b0429',
42 | '#580839',
43 | '#31082b'
44 | ];
45 |
46 | this.schemes.spectrum2001 = [
47 | '#2f243f',
48 | '#3c2c55',
49 | '#4a3768',
50 | '#565270',
51 | '#6b6b7c',
52 | '#72957f',
53 | '#86ad6e',
54 | '#a1bc5e',
55 | '#b8d954',
56 | '#d3e04e',
57 | '#ccad2a',
58 | '#cc8412',
59 | '#c1521d',
60 | '#ad3821',
61 | '#8a1010',
62 | '#681717',
63 | '#531e1e',
64 | '#3d1818',
65 | '#320a1b'
66 | ];
67 |
68 | this.schemes.classic9 = [
69 | '#423d4f',
70 | '#4a6860',
71 | '#848f39',
72 | '#a2b73c',
73 | '#ddcb53',
74 | '#c5a32f',
75 | '#7d5836',
76 | '#963b20',
77 | '#7c2626',
78 | '#491d37',
79 | '#2f254a'
80 | ].reverse();
81 |
82 | this.schemes.httpStatus = {
83 | 503: '#ea5029',
84 | 502: '#d23f14',
85 | 500: '#bf3613',
86 | 410: '#efacea',
87 | 409: '#e291dc',
88 | 403: '#f457e8',
89 | 408: '#e121d2',
90 | 401: '#b92dae',
91 | 405: '#f47ceb',
92 | 404: '#a82a9f',
93 | 400: '#b263c6',
94 | 301: '#6fa024',
95 | 302: '#87c32b',
96 | 307: '#a0d84c',
97 | 304: '#28b55c',
98 | 200: '#1a4f74',
99 | 206: '#27839f',
100 | 201: '#52adc9',
101 | 202: '#7c979f',
102 | 203: '#a5b8bd',
103 | 204: '#c1cdd1'
104 | };
105 |
106 | this.schemes.colorwheel = [
107 | '#b5b6a9',
108 | '#858772',
109 | '#785f43',
110 | '#96557e',
111 | '#4682b4',
112 | '#65b9ac',
113 | '#73c03a',
114 | '#cb513a'
115 | ].reverse();
116 |
117 | this.schemes.cool = [
118 | '#5e9d2f',
119 | '#73c03a',
120 | '#4682b4',
121 | '#7bc3b8',
122 | '#a9884e',
123 | '#c1b266',
124 | '#a47493',
125 | '#c09fb5'
126 | ];
127 |
128 | this.schemes.munin = [
129 | '#00cc00',
130 | '#0066b3',
131 | '#ff8000',
132 | '#ffcc00',
133 | '#330099',
134 | '#990099',
135 | '#ccff00',
136 | '#ff0000',
137 | '#808080',
138 | '#008f00',
139 | '#00487d',
140 | '#b35a00',
141 | '#b38f00',
142 | '#6b006b',
143 | '#8fb300',
144 | '#b30000',
145 | '#bebebe',
146 | '#80ff80',
147 | '#80c9ff',
148 | '#ffc080',
149 | '#ffe680',
150 | '#aa80ff',
151 | '#ee00cc',
152 | '#ff8080',
153 | '#666600',
154 | '#ffbfff',
155 | '#00ffcc',
156 | '#cc6699',
157 | '#999900'
158 | ];
159 | };
160 |
--------------------------------------------------------------------------------
/html/scripts/mapplayer/mapplayer.js:
--------------------------------------------------------------------------------
1 | function MapPlayer(params) {
2 | //Init
3 | var frames = [];
4 | var curFrame = 0;
5 | var fps,
6 | decay, //how many frames a point will exist before fading out completely
7 | map,
8 | intervalId;
9 | var frameDrawCallback;
10 |
11 | setOptions(params);
12 |
13 | function setOptions(params) {
14 | if (params === undefined) {
15 | return;
16 | }
17 |
18 | if (params.fps === undefined && fps === undefined) {
19 | fps = 1;
20 | } else {
21 | fps = params.fps;
22 | if (intervalId) {
23 | //we are currently playing.
24 | this.pause();
25 | this.play();
26 | }
27 | }
28 |
29 | if (params.decay === undefined && decay === undefined) {
30 | decay = 5;
31 | } else {
32 | decay = params.decay;
33 | }
34 |
35 | if (params.onFrame !== undefined) {
36 | frameDrawCallback = params.onFrame;
37 | }
38 | }
39 |
40 | //Public Functions
41 |
42 | this.pushFrame = function(f) {
43 | frames.push(f);
44 | }
45 |
46 | this.drawNext = function() {
47 | if (frames.length == 0) {
48 | throw "No frames to draw";
49 | }
50 |
51 | if (curFrame + 1 > frames.length - 1) {
52 | //if next frame is off the end, wipe and go to beginning
53 | this.clear();
54 | curFrame = 0;
55 | this.draw();
56 | return;
57 | }
58 |
59 | var dimPer = -1/decay;
60 | if (frames.length < decay) {
61 | dimPer = -1/frames.length;
62 | }
63 |
64 | var dimStart = curFrame - decay;
65 | if (dimStart < 0) {
66 | dimStart = 0;
67 | }
68 |
69 | for (var i = dimStart; i <= curFrame; i++) {
70 | frames[i].setRelativeOpacity(dimPer);
71 | }
72 |
73 | curFrame++;
74 | this.draw();
75 | }
76 |
77 | this.draw = function() {
78 | if (frames.length == 0) {
79 | throw "No frames to draw";
80 | }
81 | frames[curFrame].setOpacity(1);
82 | frames[curFrame].draw();
83 | if (frameDrawCallback != undefined) {
84 | frameDrawCallback({
85 | exData: frames[curFrame].exData,
86 | index: curFrame - 0, //math to avoid ref
87 | count: this.numFrames(),
88 | });
89 | }
90 | }
91 |
92 | this.clear = function() {
93 | for (var i = 0; i < frames.length; i++) {
94 | frames[i].hide();
95 | }
96 | }
97 |
98 | this.numFrames = function() {
99 | return frames.length - 1;
100 | }
101 |
102 | this.jump = function(i) {
103 | if (i > frames.length - 1) {
104 | throw "jump() exceeded frame count";
105 | }
106 | this.clear();
107 | curFrame = i;
108 | }
109 |
110 | this.play = function() {
111 | var that = this;
112 | intervalId = setInterval(function() {that.drawNext()}, 1000 / fps);
113 | }
114 |
115 | this.pause = function() {
116 | if (this.isPlaying()) {
117 | clearInterval(intervalId);
118 | intervalId = undefined;
119 | }
120 | }
121 |
122 | this.isPlaying = function() {
123 | if (intervalId != undefined) {
124 | return true;
125 | }
126 | }
127 |
128 | this.togglePlay = function() {
129 | if (this.isPlaying()) {
130 | this.pause();
131 | } else {
132 | this.play();
133 | }
134 | }
135 |
136 | }
137 |
138 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_06.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
34 |
35 |
36 |
84 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Fixtures.Time.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Fixtures.Time');
2 |
3 | Rickshaw.Fixtures.Time = function() {
4 |
5 | var tzOffset = new Date().getTimezoneOffset() * 60;
6 |
7 | var self = this;
8 |
9 | this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
10 |
11 | this.units = [
12 | {
13 | name: 'decade',
14 | seconds: 86400 * 365.25 * 10,
15 | formatter: function(d) { return (parseInt(d.getUTCFullYear() / 10) * 10) }
16 | }, {
17 | name: 'year',
18 | seconds: 86400 * 365.25,
19 | formatter: function(d) { return d.getUTCFullYear() }
20 | }, {
21 | name: 'month',
22 | seconds: 86400 * 30.5,
23 | formatter: function(d) { return self.months[d.getUTCMonth()] }
24 | }, {
25 | name: 'week',
26 | seconds: 86400 * 7,
27 | formatter: function(d) { return self.formatDate(d) }
28 | }, {
29 | name: 'day',
30 | seconds: 86400,
31 | formatter: function(d) { return d.getUTCDate() }
32 | }, {
33 | name: '6 hour',
34 | seconds: 3600 * 6,
35 | formatter: function(d) { return self.formatTime(d) }
36 | }, {
37 | name: 'hour',
38 | seconds: 3600,
39 | formatter: function(d) { return self.formatTime(d) }
40 | }, {
41 | name: '15 minute',
42 | seconds: 60 * 15,
43 | formatter: function(d) { return self.formatTime(d) }
44 | }, {
45 | name: 'minute',
46 | seconds: 60,
47 | formatter: function(d) { return d.getUTCMinutes() }
48 | }, {
49 | name: '15 second',
50 | seconds: 15,
51 | formatter: function(d) { return d.getUTCSeconds() + 's' }
52 | }, {
53 | name: 'second',
54 | seconds: 1,
55 | formatter: function(d) { return d.getUTCSeconds() + 's' }
56 | }
57 | ];
58 |
59 | this.unit = function(unitName) {
60 | return this.units.filter( function(unit) { return unitName == unit.name } ).shift();
61 | };
62 |
63 | this.formatDate = function(d) {
64 | return d.toUTCString().match(/, (\w+ \w+ \w+)/)[1];
65 | };
66 |
67 | this.formatTime = function(d) {
68 | return d.toUTCString().match(/(\d+:\d+):/)[1];
69 | };
70 |
71 | this.ceil = function(time, unit) {
72 |
73 | if (unit.name == 'month') {
74 |
75 | var nearFuture = new Date((time + unit.seconds - 1) * 1000);
76 |
77 | var rounded = new Date(0);
78 | rounded.setUTCFullYear(nearFuture.getUTCFullYear());
79 | rounded.setUTCMonth(nearFuture.getUTCMonth());
80 | rounded.setUTCDate(1);
81 | rounded.setUTCHours(0);
82 | rounded.setUTCMinutes(0);
83 | rounded.setUTCSeconds(0);
84 | rounded.setUTCMilliseconds(0);
85 |
86 | return rounded.getTime() / 1000;
87 | }
88 |
89 | if (unit.name == 'year') {
90 |
91 | var nearFuture = new Date((time + unit.seconds - 1) * 1000);
92 |
93 | var rounded = new Date(0);
94 | rounded.setUTCFullYear(nearFuture.getUTCFullYear());
95 | rounded.setUTCMonth(0);
96 | rounded.setUTCDate(1);
97 | rounded.setUTCHours(0);
98 | rounded.setUTCMinutes(0);
99 | rounded.setUTCSeconds(0);
100 | rounded.setUTCMilliseconds(0);
101 |
102 | return rounded.getTime() / 1000;
103 | }
104 |
105 | return Math.ceil(time / unit.seconds) * unit.seconds;
106 | };
107 | };
108 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/hover.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
40 |
41 |
42 |
43 |
47 |
48 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Renderer.Bar.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Renderer.Bar');
2 |
3 | Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
4 |
5 | name: 'bar',
6 |
7 | defaults: function($super) {
8 |
9 | var defaults = Rickshaw.extend( $super(), {
10 | gapSize: 0.05,
11 | unstack: false
12 | } );
13 |
14 | delete defaults.tension;
15 | return defaults;
16 | },
17 |
18 | initialize: function($super, args) {
19 | args = args || {};
20 | this.gapSize = args.gapSize || this.gapSize;
21 | $super(args);
22 | },
23 |
24 | domain: function($super) {
25 |
26 | var domain = $super();
27 |
28 | var frequentInterval = this._frequentInterval();
29 | domain.x[1] += parseInt(frequentInterval.magnitude);
30 |
31 | return domain;
32 | },
33 |
34 | barWidth: function() {
35 |
36 | var stackedData = this.graph.stackedData || this.graph.stackData();
37 | var data = stackedData.slice(-1).shift();
38 |
39 | var frequentInterval = this._frequentInterval();
40 | var barWidth = this.graph.x(data[0].x + frequentInterval.magnitude * (1 - this.gapSize));
41 |
42 | return barWidth;
43 | },
44 |
45 | render: function() {
46 |
47 | var graph = this.graph;
48 |
49 | graph.vis.selectAll('*').remove();
50 |
51 | var barWidth = this.barWidth();
52 | var barXOffset = 0;
53 |
54 | var activeSeriesCount = graph.series.filter( function(s) { return !s.disabled; } ).length;
55 | var seriesBarWidth = this.unstack ? barWidth / activeSeriesCount : barWidth;
56 |
57 | var transform = function(d) {
58 | // add a matrix transform for negative values
59 | var matrix = [ 1, 0, 0, (d.y < 0 ? -1 : 1), 0, (d.y < 0 ? graph.y.magnitude(Math.abs(d.y)) * 2 : 0) ];
60 | return "matrix(" + matrix.join(',') + ")";
61 | };
62 |
63 | graph.series.forEach( function(series) {
64 |
65 | if (series.disabled) return;
66 |
67 | var nodes = graph.vis.selectAll("path")
68 | .data(series.stack.filter( function(d) { return d.y !== null } ))
69 | .enter().append("svg:rect")
70 | .attr("x", function(d) { return graph.x(d.x) + barXOffset })
71 | .attr("y", function(d) { return (graph.y(d.y0 + Math.abs(d.y))) * (d.y < 0 ? -1 : 1 ) })
72 | .attr("width", seriesBarWidth)
73 | .attr("height", function(d) { return graph.y.magnitude(Math.abs(d.y)) })
74 | .attr("transform", transform);
75 |
76 | Array.prototype.forEach.call(nodes[0], function(n) {
77 | n.setAttribute('fill', series.color);
78 | } );
79 |
80 | if (this.unstack) barXOffset += seriesBarWidth;
81 |
82 | }, this );
83 | },
84 |
85 | _frequentInterval: function() {
86 |
87 | var stackedData = this.graph.stackedData || this.graph.stackData();
88 | var data = stackedData.slice(-1).shift();
89 |
90 | var intervalCounts = {};
91 |
92 | for (var i = 0; i < data.length - 1; i++) {
93 | var interval = data[i + 1].x - data[i].x;
94 | intervalCounts[interval] = intervalCounts[interval] || 0;
95 | intervalCounts[interval]++;
96 | }
97 |
98 | var frequentInterval = { count: 0 };
99 |
100 | Rickshaw.keys(intervalCounts).forEach( function(i) {
101 | if (frequentInterval.count < intervalCounts[i]) {
102 |
103 | frequentInterval = {
104 | count: intervalCounts[i],
105 | magnitude: i
106 | };
107 | }
108 | } );
109 |
110 | this._frequentInterval = function() { return frequentInterval };
111 |
112 | return frequentInterval;
113 | }
114 | } );
115 |
116 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Annotate.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Annotate');
2 |
3 | Rickshaw.Graph.Annotate = function(args) {
4 |
5 | var graph = this.graph = args.graph;
6 | this.elements = { timeline: args.element };
7 |
8 | var self = this;
9 |
10 | this.data = {};
11 |
12 | this.elements.timeline.classList.add('rickshaw_annotation_timeline');
13 |
14 | this.add = function(time, content, end_time) {
15 | self.data[time] = self.data[time] || {'boxes': []};
16 | self.data[time].boxes.push({content: content, end: end_time});
17 | };
18 |
19 | this.update = function() {
20 |
21 | Rickshaw.keys(self.data).forEach( function(time) {
22 |
23 | var annotation = self.data[time];
24 | var left = self.graph.x(time);
25 |
26 | if (left < 0 || left > self.graph.x.range()[1]) {
27 | if (annotation.element) {
28 | annotation.line.classList.add('offscreen');
29 | annotation.element.style.display = 'none';
30 | }
31 |
32 | annotation.boxes.forEach( function(box) {
33 | if ( box.rangeElement ) box.rangeElement.classList.add('offscreen');
34 | });
35 |
36 | return;
37 | }
38 |
39 | if (!annotation.element) {
40 | var element = annotation.element = document.createElement('div');
41 | element.classList.add('annotation');
42 | this.elements.timeline.appendChild(element);
43 | element.addEventListener('click', function(e) {
44 | element.classList.toggle('active');
45 | annotation.line.classList.toggle('active');
46 | annotation.boxes.forEach( function(box) {
47 | if ( box.rangeElement ) box.rangeElement.classList.toggle('active');
48 | });
49 | }, false);
50 |
51 | }
52 |
53 | annotation.element.style.left = left + 'px';
54 | annotation.element.style.display = 'block';
55 |
56 | annotation.boxes.forEach( function(box) {
57 |
58 |
59 | var element = box.element;
60 |
61 | if (!element) {
62 | element = box.element = document.createElement('div');
63 | element.classList.add('content');
64 | element.innerHTML = box.content;
65 | annotation.element.appendChild(element);
66 |
67 | annotation.line = document.createElement('div');
68 | annotation.line.classList.add('annotation_line');
69 | self.graph.element.appendChild(annotation.line);
70 |
71 | if ( box.end ) {
72 | box.rangeElement = document.createElement('div');
73 | box.rangeElement.classList.add('annotation_range');
74 | self.graph.element.appendChild(box.rangeElement);
75 | }
76 |
77 | }
78 |
79 | if ( box.end ) {
80 |
81 | var annotationRangeStart = left;
82 | var annotationRangeEnd = Math.min( self.graph.x(box.end), self.graph.x.range()[1] );
83 |
84 | // annotation makes more sense at end
85 | if ( annotationRangeStart > annotationRangeEnd ) {
86 | annotationRangeEnd = left;
87 | annotationRangeStart = Math.max( self.graph.x(box.end), self.graph.x.range()[0] );
88 | }
89 |
90 | var annotationRangeWidth = annotationRangeEnd - annotationRangeStart;
91 |
92 | box.rangeElement.style.left = annotationRangeStart + 'px';
93 | box.rangeElement.style.width = annotationRangeWidth + 'px'
94 |
95 | box.rangeElement.classList.remove('offscreen');
96 | }
97 |
98 | annotation.line.classList.remove('offscreen');
99 | annotation.line.style.left = left + 'px';
100 | } );
101 | }, this );
102 | };
103 |
104 | this.graph.onUpdate( function() { self.update() } );
105 | };
106 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/js/extensions.js:
--------------------------------------------------------------------------------
1 | var RenderControls = function(args) {
2 |
3 | this.initialize = function() {
4 |
5 | this.element = args.element;
6 | this.graph = args.graph;
7 | this.settings = this.serialize();
8 |
9 | this.inputs = {
10 | renderer: this.element.elements.renderer,
11 | interpolation: this.element.elements.interpolation,
12 | offset: this.element.elements.offset
13 | };
14 |
15 | this.element.addEventListener('change', function(e) {
16 |
17 | this.settings = this.serialize();
18 |
19 | if (e.target.name == 'renderer') {
20 | this.setDefaultOffset(e.target.value);
21 | }
22 |
23 | this.syncOptions();
24 | this.settings = this.serialize();
25 |
26 | var config = {
27 | renderer: this.settings.renderer,
28 | interpolation: this.settings.interpolation
29 | };
30 |
31 | if (this.settings.offset == 'value') {
32 | config.unstack = true;
33 | config.offset = 'zero';
34 | } else if (this.settings.offset == 'expand') {
35 | config.unstack = true;
36 | config.offset = this.settings.offset;
37 | } else {
38 | config.unstack = false;
39 | config.offset = this.settings.offset;
40 | }
41 |
42 | this.graph.configure(config);
43 | this.graph.render();
44 |
45 | }.bind(this), false);
46 | }
47 |
48 | this.serialize = function() {
49 |
50 | var values = {};
51 | var pairs = $(this.element).serializeArray();
52 |
53 | pairs.forEach( function(pair) {
54 | values[pair.name] = pair.value;
55 | } );
56 |
57 | return values;
58 | };
59 |
60 | this.syncOptions = function() {
61 |
62 | var options = this.rendererOptions[this.settings.renderer];
63 |
64 | Array.prototype.forEach.call(this.inputs.interpolation, function(input) {
65 |
66 | if (options.interpolation) {
67 | input.disabled = false;
68 | input.parentNode.classList.remove('disabled');
69 | } else {
70 | input.disabled = true;
71 | input.parentNode.classList.add('disabled');
72 | }
73 | });
74 |
75 | Array.prototype.forEach.call(this.inputs.offset, function(input) {
76 |
77 | if (options.offset.filter( function(o) { return o == input.value } ).length) {
78 | input.disabled = false;
79 | input.parentNode.classList.remove('disabled');
80 |
81 | } else {
82 | input.disabled = true;
83 | input.parentNode.classList.add('disabled');
84 | }
85 |
86 | }.bind(this));
87 |
88 | };
89 |
90 | this.setDefaultOffset = function(renderer) {
91 |
92 | var options = this.rendererOptions[renderer];
93 |
94 | if (options.defaults && options.defaults.offset) {
95 |
96 | Array.prototype.forEach.call(this.inputs.offset, function(input) {
97 | if (input.value == options.defaults.offset) {
98 | input.checked = true;
99 | } else {
100 | input.checked = false;
101 | }
102 |
103 | }.bind(this));
104 | }
105 | };
106 |
107 | this.rendererOptions = {
108 |
109 | area: {
110 | interpolation: true,
111 | offset: ['zero', 'wiggle', 'expand', 'value'],
112 | defaults: { offset: 'zero' }
113 | },
114 | line: {
115 | interpolation: true,
116 | offset: ['expand', 'value'],
117 | defaults: { offset: 'value' }
118 | },
119 | bar: {
120 | interpolation: false,
121 | offset: ['zero', 'wiggle', 'expand', 'value'],
122 | defaults: { offset: 'zero' }
123 | },
124 | scatterplot: {
125 | interpolation: false,
126 | offset: ['value'],
127 | defaults: { offset: 'value' }
128 | }
129 | };
130 |
131 | this.initialize();
132 | };
133 |
134 |
--------------------------------------------------------------------------------
/clean_calls.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php
2 | $end_ts) {
67 | //continue;
68 | }
69 |
70 | $line = array_map('cleanVal', $line);
71 | /*
72 | Array
73 | (
74 | [0] => Incident Number
75 | [1] => Type (code)
76 | [2] => Description (code description)
77 | [3] => Date/Time
78 | [4] => Address
79 | )
80 | */
81 | //associative tables in csv 'cuz I can
82 | $type_id = array_search($line[1], $types);
83 | if ($type_id === false) {
84 | $types[] = $line[1];
85 | $type_id = count($types);
86 | fwrite($fp_type_out, "$type_id,{$line[1]},\"{$line[2]}\"\n");
87 | $t++;
88 | } else {
89 | $type_id++; //array_search and count() use different bases for 'first item'
90 | }
91 |
92 | /* XXX This is what's needed to make the sense of incident types!
93 | unset($line[1]);
94 | $line[2] = $type_id;
95 | */
96 | unset($line[2]);
97 | //$line[2] = $line[2];
98 |
99 | $line[3] = date("Y-m-d H:i:s", $ts);
100 |
101 | //$line[4] is overloaded
102 | $loc = explode("\n", $line[4]);
103 | $line[4] = "\"{$loc[0]}\""; //address
104 | //$loc[1] is always 'Madison, WI' so not included
105 | $loc[2] = str_replace('(', '', $loc[2]);
106 | $loc[2] = str_replace(')', '', $loc[2]);
107 | $coords = explode(",", $loc[2]);
108 | $coords = array_map('trim', $coords);
109 | $line[5] = $coords[0]; //lat
110 | $line[6] = $coords[1]; //lng
111 |
112 | //make date the first column
113 | $temp = $line[0];
114 | $line[0] = $line[3];
115 | $line[3] = $temp;
116 |
117 | fwrite($fp_out, implode(',', $line) . "\n");
118 | $j++;
119 |
120 | /*
121 | if ($j > 5) {
122 | die();
123 | }
124 | */
125 |
126 | echo "\r$i lines, $j in date range ...";
127 | }
128 | echo "\n";
129 |
130 | echo "Sorting by date ...\n";
131 | fclose($fp_out);
132 |
133 | system("sort $output_file -o $output_file");
134 | echo "Done!\n";
135 | echo "Found $t incident types.\n";
136 |
137 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tutorial/example_07.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
41 |
42 |
107 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
60 | Rickshaw Examples
61 |
62 |
63 |
64 |
65 |
66 |
67 | Bare minimum to get a graph on the page with a couple of points.
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Basic lines with a legend and x-axis ticks and labels. Toggle lines on and off by clicking checkmarks.
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | Dig into continously updating data. Change line interpolations, zoom in on the x-axis, apply smoothing, stack and un-stack, drag and drop to re-order the stack, toggle data on and off.
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | Basic scatter plot with two overlapping series.
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Requests per second by HTTP status as stacked bars. Colors come from a deterministic palette that can carry across graphs.
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | A number of color schemes are built in. You can specify your own too.
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | Interpolate color schemes for graphs with many series.
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | Ask Rickshaw to fetch data via AJAX, rather than specifying in the constructor. There's a JSONP impelementation too.
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | Draw Y-Axis tick marks and grid lines with abbreviated numbers.
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Series.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Series');
2 |
3 | Rickshaw.Series = Rickshaw.Class.create( Array, {
4 |
5 | initialize: function (data, palette, options) {
6 |
7 | options = options || {}
8 |
9 | this.palette = new Rickshaw.Color.Palette(palette);
10 |
11 | this.timeBase = typeof(options.timeBase) === 'undefined' ?
12 | Math.floor(new Date().getTime() / 1000) :
13 | options.timeBase;
14 |
15 | var timeInterval = typeof(options.timeInterval) == 'undefined' ?
16 | 1000 :
17 | options.timeInterval;
18 |
19 | this.setTimeInterval(timeInterval);
20 |
21 | if (data && (typeof(data) == "object") && (data instanceof Array)) {
22 | data.forEach( function(item) { this.addItem(item) }, this );
23 | }
24 | },
25 |
26 | addItem: function(item) {
27 |
28 | if (typeof(item.name) === 'undefined') {
29 | throw('addItem() needs a name');
30 | }
31 |
32 | item.color = (item.color || this.palette.color(item.name));
33 | item.data = (item.data || []);
34 |
35 | // backfill, if necessary
36 | if ((item.data.length == 0) && this.length && (this.getIndex() > 0)) {
37 | this[0].data.forEach( function(plot) {
38 | item.data.push({ x: plot.x, y: 0 });
39 | } );
40 | } else if (item.data.length == 0) {
41 | item.data.push({ x: this.timeBase - (this.timeInterval || 0), y: 0 });
42 | }
43 |
44 | this.push(item);
45 |
46 | if (this.legend) {
47 | this.legend.addLine(this.itemByName(item.name));
48 | }
49 | },
50 |
51 | addData: function(data) {
52 |
53 | var index = this.getIndex();
54 |
55 | Rickshaw.keys(data).forEach( function(name) {
56 | if (! this.itemByName(name)) {
57 | this.addItem({ name: name });
58 | }
59 | }, this );
60 |
61 | this.forEach( function(item) {
62 | item.data.push({
63 | x: (index * this.timeInterval || 1) + this.timeBase,
64 | y: (data[item.name] || 0)
65 | });
66 | }, this );
67 | },
68 |
69 | getIndex: function () {
70 | return (this[0] && this[0].data && this[0].data.length) ? this[0].data.length : 0;
71 | },
72 |
73 | itemByName: function(name) {
74 |
75 | for (var i = 0; i < this.length; i++) {
76 | if (this[i].name == name)
77 | return this[i];
78 | }
79 | },
80 |
81 | setTimeInterval: function(iv) {
82 | this.timeInterval = iv / 1000;
83 | },
84 |
85 | setTimeBase: function (t) {
86 | this.timeBase = t;
87 | },
88 |
89 | dump: function() {
90 |
91 | var data = {
92 | timeBase: this.timeBase,
93 | timeInterval: this.timeInterval,
94 | items: []
95 | };
96 |
97 | this.forEach( function(item) {
98 |
99 | var newItem = {
100 | color: item.color,
101 | name: item.name,
102 | data: []
103 | };
104 |
105 | item.data.forEach( function(plot) {
106 | newItem.data.push({ x: plot.x, y: plot.y });
107 | } );
108 |
109 | data.items.push(newItem);
110 | } );
111 |
112 | return data;
113 | },
114 |
115 | load: function(data) {
116 |
117 | if (data.timeInterval) {
118 | this.timeInterval = data.timeInterval;
119 | }
120 |
121 | if (data.timeBase) {
122 | this.timeBase = data.timeBase;
123 | }
124 |
125 | if (data.items) {
126 | data.items.forEach( function(item) {
127 | this.push(item);
128 | if (this.legend) {
129 | this.legend.addLine(this.itemByName(item.name));
130 | }
131 |
132 | }, this );
133 | }
134 | }
135 | } );
136 |
137 | Rickshaw.Series.zeroFill = function(series) {
138 | Rickshaw.Series.fill(series, 0);
139 | };
140 |
141 | Rickshaw.Series.fill = function(series, fill) {
142 |
143 | var x;
144 | var i = 0;
145 |
146 | var data = series.map( function(s) { return s.data } );
147 |
148 | while ( i < Math.max.apply(null, data.map( function(d) { return d.length } )) ) {
149 |
150 | x = Math.min.apply( null,
151 | data
152 | .filter(function(d) { return d[i] })
153 | .map(function(d) { return d[i].x })
154 | );
155 |
156 | data.forEach( function(d) {
157 | if (!d[i] || d[i].x != x) {
158 | d.splice(i, 0, { x: x, y: fill });
159 | }
160 | } );
161 |
162 | i++;
163 | }
164 | };
165 |
166 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Renderer.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace("Rickshaw.Graph.Renderer");
2 |
3 | Rickshaw.Graph.Renderer = Rickshaw.Class.create( {
4 |
5 | initialize: function(args) {
6 | this.graph = args.graph;
7 | this.tension = args.tension || this.tension;
8 | this.graph.unstacker = this.graph.unstacker || new Rickshaw.Graph.Unstacker( { graph: this.graph } );
9 | this.configure(args);
10 | },
11 |
12 | seriesPathFactory: function() {
13 | //implement in subclass
14 | },
15 |
16 | seriesStrokeFactory: function() {
17 | // implement in subclass
18 | },
19 |
20 | defaults: function() {
21 | return {
22 | tension: 0.8,
23 | strokeWidth: 2,
24 | unstack: true,
25 | padding: { top: 0.01, right: 0, bottom: 0.01, left: 0 },
26 | stroke: false,
27 | fill: false
28 | };
29 | },
30 |
31 | domain: function() {
32 |
33 | var values = { xMin: [], xMax: [], y: [] };
34 |
35 | var stackedData = this.graph.stackedData || this.graph.stackData();
36 | var firstPoint = stackedData[0][0];
37 |
38 | var xMin = firstPoint.x;
39 | var xMax = firstPoint.x
40 |
41 | var yMin = firstPoint.y + firstPoint.y0;
42 | var yMax = firstPoint.y + firstPoint.y0;
43 |
44 | stackedData.forEach( function(series) {
45 |
46 | series.forEach( function(d) {
47 |
48 | var y = d.y + d.y0;
49 |
50 | if (y < yMin) yMin = y;
51 | if (y > yMax) yMax = y;
52 | } );
53 |
54 | if (series[0].x < xMin) xMin = series[0].x;
55 | if (series[series.length - 1].x > xMax) xMax = series[series.length - 1].x;
56 | } );
57 |
58 | xMin -= (xMax - xMin) * this.padding.left;
59 | xMax += (xMax - xMin) * this.padding.right;
60 |
61 | yMin = this.graph.min === 'auto' ? yMin : this.graph.min || 0;
62 | yMax = this.graph.max || yMax;
63 |
64 | if (this.graph.min === 'auto' || yMin < 0) {
65 | yMin -= (yMax - yMin) * this.padding.bottom;
66 | }
67 |
68 | if (this.graph.max === undefined) {
69 | yMax += (yMax - yMin) * this.padding.top;
70 | }
71 |
72 | return { x: [xMin, xMax], y: [yMin, yMax] };
73 | },
74 |
75 | render: function() {
76 |
77 | var graph = this.graph;
78 |
79 | graph.vis.selectAll('*').remove();
80 |
81 | var nodes = graph.vis.selectAll("path")
82 | .data(this.graph.stackedData)
83 | .enter().append("svg:path")
84 | .attr("d", this.seriesPathFactory());
85 |
86 | var i = 0;
87 | graph.series.forEach( function(series) {
88 | if (series.disabled) return;
89 | series.path = nodes[0][i++];
90 | this._styleSeries(series);
91 | }, this );
92 | },
93 |
94 | _styleSeries: function(series) {
95 |
96 | var fill = this.fill ? series.color : 'none';
97 | var stroke = this.stroke ? series.color : 'none';
98 |
99 | series.path.setAttribute('fill', fill);
100 | series.path.setAttribute('stroke', stroke);
101 | series.path.setAttribute('stroke-width', this.strokeWidth);
102 | series.path.setAttribute('class', series.className);
103 | },
104 |
105 | configure: function(args) {
106 |
107 | args = args || {};
108 |
109 | Rickshaw.keys(this.defaults()).forEach( function(key) {
110 |
111 | if (!args.hasOwnProperty(key)) {
112 | this[key] = this[key] || this.graph[key] || this.defaults()[key];
113 | return;
114 | }
115 |
116 | if (typeof this.defaults()[key] == 'object') {
117 |
118 | Rickshaw.keys(this.defaults()[key]).forEach( function(k) {
119 |
120 | this[key][k] =
121 | args[key][k] !== undefined ? args[key][k] :
122 | this[key][k] !== undefined ? this[key][k] :
123 | this.defaults()[key][k];
124 | }, this );
125 |
126 | } else {
127 | this[key] =
128 | args[key] !== undefined ? args[key] :
129 | this[key] !== undefined ? this[key] :
130 | this.graph[key] !== undefined ? this.graph[key] :
131 | this.defaults()[key];
132 | }
133 |
134 | }, this );
135 | },
136 |
137 | setStrokeWidth: function(strokeWidth) {
138 | if (strokeWidth !== undefined) {
139 | this.strokeWidth = strokeWidth;
140 | }
141 | },
142 |
143 | setTension: function(tension) {
144 | if (tension !== undefined) {
145 | this.tension = tension;
146 | }
147 | }
148 | } );
149 |
150 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Compat.ClassList.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Compat.ClassList');
2 |
3 | Rickshaw.Compat.ClassList = function() {
4 |
5 | /* adapted from http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
6 |
7 | if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
8 |
9 | (function (view) {
10 |
11 | "use strict";
12 |
13 | var
14 | classListProp = "classList"
15 | , protoProp = "prototype"
16 | , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
17 | , objCtr = Object
18 | , strTrim = String[protoProp].trim || function () {
19 | return this.replace(/^\s+|\s+$/g, "");
20 | }
21 | , arrIndexOf = Array[protoProp].indexOf || function (item) {
22 | var
23 | i = 0
24 | , len = this.length
25 | ;
26 | for (; i < len; i++) {
27 | if (i in this && this[i] === item) {
28 | return i;
29 | }
30 | }
31 | return -1;
32 | }
33 | // Vendors: please allow content code to instantiate DOMExceptions
34 | , DOMEx = function (type, message) {
35 | this.name = type;
36 | this.code = DOMException[type];
37 | this.message = message;
38 | }
39 | , checkTokenAndGetIndex = function (classList, token) {
40 | if (token === "") {
41 | throw new DOMEx(
42 | "SYNTAX_ERR"
43 | , "An invalid or illegal string was specified"
44 | );
45 | }
46 | if (/\s/.test(token)) {
47 | throw new DOMEx(
48 | "INVALID_CHARACTER_ERR"
49 | , "String contains an invalid character"
50 | );
51 | }
52 | return arrIndexOf.call(classList, token);
53 | }
54 | , ClassList = function (elem) {
55 | var
56 | trimmedClasses = strTrim.call(elem.className)
57 | , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
58 | , i = 0
59 | , len = classes.length
60 | ;
61 | for (; i < len; i++) {
62 | this.push(classes[i]);
63 | }
64 | this._updateClassName = function () {
65 | elem.className = this.toString();
66 | };
67 | }
68 | , classListProto = ClassList[protoProp] = []
69 | , classListGetter = function () {
70 | return new ClassList(this);
71 | }
72 | ;
73 | // Most DOMException implementations don't allow calling DOMException's toString()
74 | // on non-DOMExceptions. Error's toString() is sufficient here.
75 | DOMEx[protoProp] = Error[protoProp];
76 | classListProto.item = function (i) {
77 | return this[i] || null;
78 | };
79 | classListProto.contains = function (token) {
80 | token += "";
81 | return checkTokenAndGetIndex(this, token) !== -1;
82 | };
83 | classListProto.add = function (token) {
84 | token += "";
85 | if (checkTokenAndGetIndex(this, token) === -1) {
86 | this.push(token);
87 | this._updateClassName();
88 | }
89 | };
90 | classListProto.remove = function (token) {
91 | token += "";
92 | var index = checkTokenAndGetIndex(this, token);
93 | if (index !== -1) {
94 | this.splice(index, 1);
95 | this._updateClassName();
96 | }
97 | };
98 | classListProto.toggle = function (token) {
99 | token += "";
100 | if (checkTokenAndGetIndex(this, token) === -1) {
101 | this.add(token);
102 | } else {
103 | this.remove(token);
104 | }
105 | };
106 | classListProto.toString = function () {
107 | return this.join(" ");
108 | };
109 |
110 | if (objCtr.defineProperty) {
111 | var classListPropDesc = {
112 | get: classListGetter
113 | , enumerable: true
114 | , configurable: true
115 | };
116 | try {
117 | objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
118 | } catch (ex) { // IE 8 doesn't support enumerable:true
119 | if (ex.number === -0x7FF5EC54) {
120 | classListPropDesc.enumerable = false;
121 | objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
122 | }
123 | }
124 | } else if (objCtr[protoProp].__defineGetter__) {
125 | elemCtrProto.__defineGetter__(classListProp, classListGetter);
126 | }
127 |
128 | }(window));
129 |
130 | }
131 | };
132 |
133 | if ( (typeof RICKSHAW_NO_COMPAT !== "undefined" && !RICKSHAW_NO_COMPAT) || typeof RICKSHAW_NO_COMPAT === "undefined") {
134 | new Rickshaw.Compat.ClassList();
135 | }
136 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/css/extensions.css:
--------------------------------------------------------------------------------
1 | div, span, p, td {
2 | font-family: Arial, sans-serif;
3 | }
4 | #content {
5 | width: 1200px;
6 | }
7 | #chart {
8 | display: inline-block;
9 | }
10 | #chart path {
11 | -webkit-transition: opacity 0.2s linear;
12 | }
13 | #slider {
14 | margin-top: 10px;
15 | }
16 | #legend {
17 | display: inline-block;
18 | position: relative;
19 | left: 8px;
20 | }
21 | #legend_container {
22 | position: absolute;
23 | right: 0;
24 | bottom: 26px;
25 | width: 0;
26 | }
27 | #chart_container {
28 | position: relative;
29 | display: inline-block;
30 | }
31 | #smoother {
32 | margin: 0 0 10px 16px;
33 | width: 100px;
34 | }
35 | .rickshaw_graph .detail {
36 | left: -1000;
37 | }
38 | #chart {
39 | border: 1px solid #f0f0f0;
40 | }
41 | #side_panel {
42 | padding: 0 20px 20px 0;
43 | width: 240px;
44 | display: inline-block;
45 | vertical-align: top;
46 | }
47 | #side_panel section {
48 | color: #505050;
49 | font-size: 12px;
50 | }
51 | #side_panel section h6 {
52 | margin: 0 0 1em 0;
53 | font-size: 12px;
54 | font-weight: normal;
55 | }
56 | #side_panel .ui-slider-horizontal {
57 | height: 1px !important;
58 | border-color: #e0e0e0;
59 | margin-bottom: 10px;
60 | }
61 | #side_panel .ui-slider-handle {
62 | border-color: #a0a0a0;
63 | height: 9px !important;
64 | width: 9px !important;
65 | top: -5px !important;
66 | border-radius: 6px;
67 | outline: none;
68 | cursor: pointer;
69 | }
70 | #legend {
71 | background-color: white;
72 | margin-left: 0;
73 | padding: 0;
74 | left: 0;
75 | }
76 | #legend .label {
77 | color: #404040;
78 | }
79 | #legend .action {
80 | color: black;
81 | opacity: 0.5;
82 | }
83 | #legend ul {
84 | padding: 0;
85 | }
86 | h1 {
87 | font-family: Franklin Gothic Medium, UnDotum, Helvetica, Arial;
88 | font-weight: normal;
89 | font-size: 20px;
90 | }
91 | section {
92 | border: none;
93 | border-top: 1px solid #eaeaea;
94 | padding: 15px 0;
95 | }
96 | #smoother {
97 | margin: 5px 0 0 10px;
98 | width: 90%;
99 | }
100 | label.disabled {
101 | opacity: 0.4;
102 | }
103 | #renderer_form.toggler {
104 | display: block;
105 | margin: 0;
106 | }
107 | #renderer_form.toggler input[type=radio]:checked {
108 | outline: 2px solid steelblue;
109 | }
110 | #renderer_form.toggler input[type=radio] {
111 | -moz-appearance: button;
112 | background: white;
113 | margin: 0 7px;
114 | width: 39px;
115 | height: 26px;
116 | position: absolute;
117 | }
118 | #renderer_form.toggler label {
119 | display: inline-block;
120 | padding: 0;
121 | width: 39px;
122 | padding-top: 27px;
123 | text-align: center;
124 | font-size: 10px;
125 | color: #808080;
126 | background-repeat: no-repeat;
127 | position: relative;
128 | margin: 0 7px;
129 | cursor: pointer;
130 | }
131 | #interpolation_form,
132 | #offset_form {
133 | vertical-align: top;
134 | display: inline-block;
135 | width: 45%;
136 | }
137 | #interpolation_form label,
138 | #offset_form label {
139 | display: block;
140 | }
141 | label[for=area] {
142 | background: url(../images/om_stack.png);
143 | }
144 | label[for=line] {
145 | background: url(../images/om_lines.png);
146 | }
147 | label[for=bar] {
148 | background: url(../images/om_bar.png);
149 | }
150 | label[for=scatter] {
151 | background: url(../images/om_scatter.png);
152 | }
153 | #offset_form label,
154 | #interpolation_form label {
155 | background-repeat: no-repeat;
156 | background-position: 2em center;
157 | cursor: pointer;
158 | cursor: hand;
159 | }
160 | #offset_form label span,
161 | #interpolation_form label span {
162 | padding-left: 36px;
163 | }
164 | label[for=stack] {
165 | background-image: url(../images/offset_stack.png);
166 | }
167 | label[for=pct] {
168 | background-image: url(../images/offset_pct.png);
169 | }
170 | label[for=stream] {
171 | background-image: url(../images/offset_stream.png);
172 | }
173 | label[for=value] {
174 | background-image: url(../images/offset_value.png);
175 | }
176 | label[for=cardinal] {
177 | background-image: url(../images/interp_cardinal.png);
178 | }
179 | label[for=linear] {
180 | background-image: url(../images/interp_linear.png);
181 | }
182 | label[for=step] {
183 | background-image: url(../images/interp_step.png);
184 | }
185 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/tests/Rickshaw.Series.js:
--------------------------------------------------------------------------------
1 | var Rickshaw = require("../rickshaw");
2 |
3 | function seriesData() {
4 | return {
5 | name: 'series1',
6 | data: [ {x: 0, y: 20}, {x: 1, y: 21}, { x: 2, y: 15} ],
7 | color: 'red'
8 | };
9 | }
10 |
11 | exports.basic = function(test) {
12 |
13 | test.equal(typeof Rickshaw.Series, 'function', 'Rickshaw.Series is a function');
14 | test.done();
15 | };
16 |
17 | exports.initialize = function(test) {
18 |
19 | var series = new Rickshaw.Series([seriesData()], 'spectrum2001', {timeBase: 0});
20 |
21 | test.ok(series instanceof Rickshaw.Series);
22 | test.ok(series instanceof Array);
23 |
24 | test.deepEqual(
25 | series[0].data,
26 | [ { x: 0, y: 20 },
27 | { x: 1, y: 21 },
28 | { x: 2, y: 15 } ],
29 | 'data made it in as we expect'
30 | );
31 |
32 | test.done();
33 | };
34 |
35 | exports.addItem = function(test) {
36 |
37 | var series = new Rickshaw.Series([seriesData()], 'spectrum2001', {timeBase: 0});
38 |
39 | series.addItem( {
40 | name: 'series2',
41 | data: [ {x: 0, y: 10}, {x: 1, y: 13}, {x: 2, y: 12} ]
42 | } );
43 |
44 | test.equal(series.length, 2, 'series has two items');
45 | test.done();
46 | }
47 |
48 | exports.addData = function(test) {
49 |
50 | var series = new Rickshaw.Series([seriesData()], 'spectrum2001', {timeBase: 0});
51 |
52 | series.addData( { series1: 22, } );
53 |
54 | test.equal(series[0].data.length, 4, 'first series has four data points');
55 | test.equal(series[0].data[3].y, 22, 'first series last data point made it in');
56 |
57 | series.addData( { series1: 29, series2: 57 } );
58 |
59 | test.equal(series[0].data[4].y, 29, 'first series has a new data point');
60 |
61 | test.equal(series[1].data.length, 5, 'second series has five data points');
62 | test.equal(series[1].data[4].y, 57, 'second series last data point made it in');
63 |
64 | test.done();
65 | }
66 |
67 | exports.itemByName = function(test) {
68 |
69 | var series = new Rickshaw.Series([seriesData()], 'spectrum2001', {timeBase: 0});
70 |
71 | test.strictEqual(series.itemByName('series1'), series[0], 'we get the right item');
72 | test.strictEqual(series.itemByName('series1').name, 'series1', 'item by name is right');
73 | test.done();
74 | }
75 |
76 | exports.dump = function(test) {
77 |
78 | var series = new Rickshaw.Series([seriesData()], 'spectrum2001', {timeBase: 0});
79 |
80 | test.deepEqual(
81 | series.dump(),
82 | {
83 | "timeBase":0,
84 | "timeInterval": 1,
85 | "items":[{
86 | "color":"red",
87 | "name":"series1",
88 | "data":[{"x":0,"y":20},{"x":1,"y":21},{"x":2,"y":15}]
89 | }]
90 | },
91 | 'dumped series matches'
92 | );
93 |
94 | test.done();
95 | }
96 |
97 | exports.zeroFill = function(test) {
98 |
99 | var series = [
100 | { name: "series1", data: [{ x: 1, y: 22 }, { x: 3, y: 29 }] },
101 | { name: "series2", data: [{ x: 2, y: 49 }] }
102 | ];
103 |
104 | Rickshaw.Series.zeroFill(series);
105 |
106 | var expectedSeries = [
107 | { name: "series1", data: [{ x: 1, y: 22 }, { x: 2, y: 0 }, { x: 3, y: 29 }] },
108 | { name: "series2", data: [{ x: 1, y: 0}, { x: 2, y: 49 }, { x: 3, y: 0 }] }
109 | ];
110 |
111 | test.deepEqual(series, expectedSeries, "zero fill fills in zeros");
112 | test.done();
113 | }
114 |
115 | exports.nullFill = function(test) {
116 |
117 | var series = [
118 | { name: "series1", data: [{ x: 1, y: 22 }, { x: 3, y: 29 }] },
119 | { name: "series2", data: [{ x: 2, y: 49 }] }
120 | ];
121 |
122 | Rickshaw.Series.fill(series, null);
123 |
124 | var expectedSeries = [
125 | { name: "series1", data: [{ x: 1, y: 22 }, { x: 2, y: null }, { x: 3, y: 29 }] },
126 | { name: "series2", data: [{ x: 1, y: null}, { x: 2, y: 49 }, { x: 3, y: null }] }
127 | ];
128 |
129 | test.deepEqual(series, expectedSeries, "null fill fills in nulls");
130 | test.done();
131 | }
132 |
133 | exports.load = function(test) {
134 |
135 | var series = new Rickshaw.Series([], 'spectrum2001', {timeBase: 0});
136 |
137 | series.load({
138 | items: [ seriesData() ],
139 | timeInterval: 3,
140 | timeBase: 0
141 | });
142 |
143 | delete series.palette;
144 |
145 | test.equal(series.timeBase, 0, 'time base made it in');
146 | test.equal(series.timeInterval, 3, 'time interval made it in');
147 | test.equal(series[0].data.length, 3, 'series data made it in');
148 | test.done();
149 | }
150 | /*
151 | */
152 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/css/graph.css:
--------------------------------------------------------------------------------
1 | /* graph */
2 |
3 | .rickshaw_graph {
4 | position: relative;
5 | }
6 | .rickshaw_graph svg {
7 | display: block;
8 | overflow: hidden;
9 | }
10 |
11 | /* ticks */
12 |
13 | .rickshaw_graph .x_tick {
14 | position: absolute;
15 | top: 0;
16 | bottom: 0;
17 | width: 0px;
18 | border-left: 1px dotted rgba(0, 0, 0, 0.2);
19 | pointer-events: none;
20 | }
21 | .rickshaw_graph .x_tick .title {
22 | position: absolute;
23 | font-size: 12px;
24 | font-family: Arial, sans-serif;
25 | opacity: 0.5;
26 | white-space: nowrap;
27 | margin-left: 3px;
28 | bottom: 1px;
29 | }
30 |
31 | /* annotations */
32 |
33 | .rickshaw_annotation_timeline {
34 | height: 1px;
35 | border-top: 1px solid #e0e0e0;
36 | margin-top: 10px;
37 | position: relative;
38 | }
39 | .rickshaw_annotation_timeline .annotation {
40 | position: absolute;
41 | height: 6px;
42 | width: 6px;
43 | margin-left: -2px;
44 | top: -3px;
45 | border-radius: 5px;
46 | background-color: rgba(0, 0, 0, 0.25);
47 | }
48 | .rickshaw_graph .annotation_line {
49 | position: absolute;
50 | top: 0;
51 | bottom: -6px;
52 | width: 0px;
53 | border-left: 2px solid rgba(0, 0, 0, 0.3);
54 | display: none;
55 | }
56 | .rickshaw_graph .annotation_line.active {
57 | display: block;
58 | }
59 |
60 | .rickshaw_graph .annotation_range {
61 | background: rgba(0, 0, 0, 0.1);
62 | display: none;
63 | position: absolute;
64 | top: 0;
65 | bottom: -6px;
66 | z-index: -10;
67 | }
68 | .rickshaw_graph .annotation_range.active {
69 | display: block;
70 | }
71 | .rickshaw_graph .annotation_range.active.offscreen {
72 | display: none;
73 | }
74 |
75 | .rickshaw_annotation_timeline .annotation .content {
76 | background: white;
77 | color: black;
78 | opacity: 0.9;
79 | padding: 5px 5px;
80 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
81 | border-radius: 3px;
82 | position: relative;
83 | z-index: 20;
84 | font-size: 12px;
85 | padding: 6px 8px 8px;
86 | top: 18px;
87 | left: -11px;
88 | width: 160px;
89 | display: none;
90 | cursor: pointer;
91 | }
92 | .rickshaw_annotation_timeline .annotation .content:before {
93 | content: "\25b2";
94 | position: absolute;
95 | top: -11px;
96 | color: white;
97 | text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8);
98 | }
99 | .rickshaw_annotation_timeline .annotation.active,
100 | .rickshaw_annotation_timeline .annotation:hover {
101 | background-color: rgba(0, 0, 0, 0.8);
102 | cursor: none;
103 | }
104 | .rickshaw_annotation_timeline .annotation .content:hover {
105 | z-index: 50;
106 | }
107 | .rickshaw_annotation_timeline .annotation.active .content {
108 | display: block;
109 | }
110 | .rickshaw_annotation_timeline .annotation:hover .content {
111 | display: block;
112 | z-index: 50;
113 | }
114 | .rickshaw_graph .y_axis {
115 | fill: none;
116 | }
117 | .rickshaw_graph .y_ticks .tick {
118 | stroke: rgba(0, 0, 0, 0.16);
119 | stroke-width: 2px;
120 | shape-rendering: crisp-edges;
121 | pointer-events: none;
122 | }
123 | .rickshaw_graph .y_grid .tick {
124 | z-index: -1;
125 | stroke: rgba(0, 0, 0, 0.20);
126 | stroke-width: 1px;
127 | stroke-dasharray: 1 1;
128 | }
129 | .rickshaw_graph .y_grid path {
130 | fill: none;
131 | stroke: none;
132 | }
133 | .rickshaw_graph .y_ticks path {
134 | fill: none;
135 | stroke: #808080;
136 | }
137 | .rickshaw_graph .y_ticks text {
138 | opacity: 0.5;
139 | font-size: 12px;
140 | pointer-events: none;
141 | }
142 | .rickshaw_graph .x_tick.glow .title,
143 | .rickshaw_graph .y_ticks.glow text {
144 | fill: black;
145 | color: black;
146 | text-shadow:
147 | -1px 1px 0 rgba(255, 255, 255, 0.1),
148 | 1px -1px 0 rgba(255, 255, 255, 0.1),
149 | 1px 1px 0 rgba(255, 255, 255, 0.1),
150 | 0px 1px 0 rgba(255, 255, 255, 0.1),
151 | 0px -1px 0 rgba(255, 255, 255, 0.1),
152 | 1px 0px 0 rgba(255, 255, 255, 0.1),
153 | -1px 0px 0 rgba(255, 255, 255, 0.1),
154 | -1px -1px 0 rgba(255, 255, 255, 0.1);
155 | }
156 | .rickshaw_graph .x_tick.inverse .title,
157 | .rickshaw_graph .y_ticks.inverse text {
158 | fill: white;
159 | color: white;
160 | text-shadow:
161 | -1px 1px 0 rgba(0, 0, 0, 0.8),
162 | 1px -1px 0 rgba(0, 0, 0, 0.8),
163 | 1px 1px 0 rgba(0, 0, 0, 0.8),
164 | 0px 1px 0 rgba(0, 0, 0, 0.8),
165 | 0px -1px 0 rgba(0, 0, 0, 0.8),
166 | 1px 0px 0 rgba(0, 0, 0, 0.8),
167 | -1px 0px 0 rgba(0, 0, 0, 0.8),
168 | -1px -1px 0 rgba(0, 0, 0, 0.8);
169 | }
170 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.Behavior.Series.Toggle.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.Behavior.Series.Toggle');
2 |
3 | Rickshaw.Graph.Behavior.Series.Toggle = function(args) {
4 |
5 | this.graph = args.graph;
6 | this.legend = args.legend;
7 |
8 | var self = this;
9 |
10 | this.addAnchor = function(line) {
11 | var anchor = document.createElement('a');
12 | anchor.innerHTML = '✔';
13 | anchor.classList.add('action');
14 | line.element.insertBefore(anchor, line.element.firstChild);
15 |
16 | anchor.onclick = function(e) {
17 | if (line.series.disabled) {
18 | line.series.enable();
19 | line.element.classList.remove('disabled');
20 | } else {
21 | line.series.disable();
22 | line.element.classList.add('disabled');
23 | }
24 | }
25 |
26 | var label = line.element.getElementsByTagName('span')[0];
27 | label.onclick = function(e){
28 |
29 | var disableAllOtherLines = line.series.disabled;
30 | if ( ! disableAllOtherLines ) {
31 | for ( var i = 0; i < self.legend.lines.length; i++ ) {
32 | var l = self.legend.lines[i];
33 | if ( line.series === l.series ) {
34 | // noop
35 | } else if ( l.series.disabled ) {
36 | // noop
37 | } else {
38 | disableAllOtherLines = true;
39 | break;
40 | }
41 | }
42 | }
43 |
44 | // show all or none
45 | if ( disableAllOtherLines ) {
46 |
47 | // these must happen first or else we try ( and probably fail ) to make a no line graph
48 | line.series.enable();
49 | line.element.classList.remove('disabled');
50 |
51 | self.legend.lines.forEach(function(l){
52 | if ( line.series === l.series ) {
53 | // noop
54 | } else {
55 | l.series.disable();
56 | l.element.classList.add('disabled');
57 | }
58 | });
59 |
60 | } else {
61 |
62 | self.legend.lines.forEach(function(l){
63 | l.series.enable();
64 | l.element.classList.remove('disabled');
65 | });
66 |
67 | }
68 |
69 | };
70 |
71 | };
72 |
73 | if (this.legend) {
74 |
75 | $(this.legend.list).sortable( {
76 | start: function(event, ui) {
77 | ui.item.bind('no.onclick',
78 | function(event) {
79 | event.preventDefault();
80 | }
81 | );
82 | },
83 | stop: function(event, ui) {
84 | setTimeout(function(){
85 | ui.item.unbind('no.onclick');
86 | }, 250);
87 | }
88 | })
89 |
90 | this.legend.lines.forEach( function(l) {
91 | self.addAnchor(l);
92 | } );
93 | }
94 |
95 | this._addBehavior = function() {
96 |
97 | this.graph.series.forEach( function(s) {
98 |
99 | s.disable = function() {
100 |
101 | if (self.graph.series.length <= 1) {
102 | throw('only one series left');
103 | }
104 |
105 | s.disabled = true;
106 | self.graph.update();
107 | };
108 |
109 | s.enable = function() {
110 | s.disabled = false;
111 | self.graph.update();
112 | };
113 | } );
114 | };
115 | this._addBehavior();
116 |
117 | this.updateBehaviour = function () { this._addBehavior() };
118 |
119 | };
120 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/rickshaw.min.css:
--------------------------------------------------------------------------------
1 | .rickshaw_graph .detail{pointer-events:none;position:absolute;top:0;z-index:2;background:rgba(0,0,0,.1);bottom:0;width:1px;transition:opacity .25s linear;-moz-transition:opacity .25s linear;-o-transition:opacity .25s linear;-webkit-transition:opacity .25s linear}.rickshaw_graph .detail.inactive{opacity:0}.rickshaw_graph .detail .item.active{opacity:1}.rickshaw_graph .detail .x_label{font-family:Arial,sans-serif;border-radius:3px;padding:6px;opacity:.5;border:1px solid #e0e0e0;font-size:12px;position:absolute;background:#fff;white-space:nowrap}.rickshaw_graph .detail .item{position:absolute;z-index:2;border-radius:3px;padding:.25em;font-size:12px;font-family:Arial,sans-serif;opacity:0;background:rgba(0,0,0,.4);color:#fff;border:1px solid rgba(0,0,0,.4);margin-left:1em;margin-top:-1em;white-space:nowrap}.rickshaw_graph .detail .item.active{opacity:1;background:rgba(0,0,0,.8)}.rickshaw_graph .detail .item:before{content:"\25c2";position:absolute;left:-.5em;color:rgba(0,0,0,.7);width:0}.rickshaw_graph .detail .dot{width:4px;height:4px;margin-left:-4px;margin-top:-3px;border-radius:5px;position:absolute;box-shadow:0 0 2px rgba(0,0,0,.6);background:#fff;border-width:2px;border-style:solid;display:none;background-clip:padding-box}.rickshaw_graph .detail .dot.active{display:block}.rickshaw_graph{position:relative}.rickshaw_graph svg{display:block;overflow:hidden}.rickshaw_graph .x_tick{position:absolute;top:0;bottom:0;width:0;border-left:1px dotted rgba(0,0,0,.2);pointer-events:none}.rickshaw_graph .x_tick .title{position:absolute;font-size:12px;font-family:Arial,sans-serif;opacity:.5;white-space:nowrap;margin-left:3px;bottom:1px}.rickshaw_annotation_timeline{height:1px;border-top:1px solid #e0e0e0;margin-top:10px;position:relative}.rickshaw_annotation_timeline .annotation{position:absolute;height:6px;width:6px;margin-left:-2px;top:-3px;border-radius:5px;background-color:rgba(0,0,0,.25)}.rickshaw_graph .annotation_line{position:absolute;top:0;bottom:-6px;width:0;border-left:2px solid rgba(0,0,0,.3);display:none}.rickshaw_graph .annotation_line.active{display:block}.rickshaw_graph .annotation_range{background:rgba(0,0,0,.1);display:none;position:absolute;top:0;bottom:-6px;z-index:-10}.rickshaw_graph .annotation_range.active{display:block}.rickshaw_graph .annotation_range.active.offscreen{display:none}.rickshaw_annotation_timeline .annotation .content{background:#fff;color:#000;opacity:.9;padding:5px 5px;box-shadow:0 0 2px rgba(0,0,0,.8);border-radius:3px;position:relative;z-index:20;font-size:12px;padding:6px 8px 8px;top:18px;left:-11px;width:160px;display:none;cursor:pointer}.rickshaw_annotation_timeline .annotation .content:before{content:"\25b2";position:absolute;top:-11px;color:#fff;text-shadow:0 -1px 1px rgba(0,0,0,.8)}.rickshaw_annotation_timeline .annotation.active,.rickshaw_annotation_timeline .annotation:hover{background-color:rgba(0,0,0,.8);cursor:none}.rickshaw_annotation_timeline .annotation .content:hover{z-index:50}.rickshaw_annotation_timeline .annotation.active .content{display:block}.rickshaw_annotation_timeline .annotation:hover .content{display:block;z-index:50}.rickshaw_graph .y_axis{fill:none}.rickshaw_graph .y_ticks .tick{stroke:rgba(0,0,0,.16);stroke-width:2px;shape-rendering:crisp-edges;pointer-events:none}.rickshaw_graph .y_grid .tick{z-index:-1;stroke:rgba(0,0,0,.20);stroke-width:1px;stroke-dasharray:1 1}.rickshaw_graph .y_grid path{fill:none;stroke:none}.rickshaw_graph .y_ticks path{fill:none;stroke:#808080}.rickshaw_graph .y_ticks text{opacity:.5;font-size:12px;pointer-events:none}.rickshaw_graph .x_tick.glow .title,.rickshaw_graph .y_ticks.glow text{fill:black;color:#000;text-shadow:-1px 1px 0 rgba(255,255,255,.1),1px -1px 0 rgba(255,255,255,.1),1px 1px 0 rgba(255,255,255,.1),0px 1px 0 rgba(255,255,255,.1),0px -1px 0 rgba(255,255,255,.1),1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1),-1px -1px 0 rgba(255,255,255,.1)}.rickshaw_graph .x_tick.inverse .title,.rickshaw_graph .y_ticks.inverse text{fill:white;color:#fff;text-shadow:-1px 1px 0 rgba(0,0,0,.8),1px -1px 0 rgba(0,0,0,.8),1px 1px 0 rgba(0,0,0,.8),0px 1px 0 rgba(0,0,0,.8),0px -1px 0 rgba(0,0,0,.8),1px 0 0 rgba(0,0,0,.8),-1px 0 0 rgba(0,0,0,.8),-1px -1px 0 rgba(0,0,0,.8)}.rickshaw_legend{font-family:Arial;font-size:12px;color:#fff;background:#404040;display:inline-block;padding:12px 5px;border-radius:2px;position:relative}.rickshaw_legend:hover{z-index:10}.rickshaw_legend .swatch{width:10px;height:10px;border:1px solid rgba(0,0,0,.2)}.rickshaw_legend .line{clear:both;line-height:140%;padding-right:15px}.rickshaw_legend .line .swatch{display:inline-block;margin-right:3px;border-radius:2px}.rickshaw_legend .label{white-space:nowrap;display:inline}.rickshaw_legend .action:hover{opacity:.6}.rickshaw_legend .action{margin-right:.2em;font-size:10px;opacity:.2;cursor:pointer;font-size:14px}.rickshaw_legend .line.disabled{opacity:.4}.rickshaw_legend ul{list-style-type:none;margin:0;padding:0;margin:2px;cursor:pointer}.rickshaw_legend li{padding:0 0 0 2px;min-width:80px;white-space:nowrap}.rickshaw_legend li:hover{background:rgba(255,255,255,.08);border-radius:3px}.rickshaw_legend li:active{background:rgba(255,255,255,.2);border-radius:3px}
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/series.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Random Data in the Future
42 |
43 |
55 |
59 |
60 |
61 |
62 |
67 |
68 |
69 |
70 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.HoverDetail.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph.HoverDetail');
2 |
3 | Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
4 |
5 | initialize: function(args) {
6 |
7 | var graph = this.graph = args.graph;
8 |
9 | this.xFormatter = args.xFormatter || function(x) {
10 | return new Date( x * 1000 ).toUTCString();
11 | };
12 |
13 | this.yFormatter = args.yFormatter || function(y) {
14 | return y === null ? y : y.toFixed(2);
15 | };
16 |
17 | var element = this.element = document.createElement('div');
18 | element.className = 'detail';
19 |
20 | this.visible = true;
21 | graph.element.appendChild(element);
22 |
23 | this.lastEvent = null;
24 | this._addListeners();
25 |
26 | this.onShow = args.onShow;
27 | this.onHide = args.onHide;
28 | this.onRender = args.onRender;
29 |
30 | this.formatter = args.formatter || this.formatter;
31 |
32 | },
33 |
34 | formatter: function(series, x, y, formattedX, formattedY, d) {
35 | return series.name + ': ' + formattedY;
36 | },
37 |
38 | update: function(e) {
39 |
40 | e = e || this.lastEvent;
41 | if (!e) return;
42 | this.lastEvent = e;
43 |
44 | if (!e.target.nodeName.match(/^(path|svg|rect)$/)) return;
45 |
46 | var graph = this.graph;
47 |
48 | var eventX = e.offsetX || e.layerX;
49 | var eventY = e.offsetY || e.layerY;
50 |
51 | var j = 0;
52 | var points = [];
53 | var nearestPoint;
54 |
55 | this.graph.series.active().forEach( function(series) {
56 |
57 | var data = this.graph.stackedData[j++];
58 |
59 | var domainX = graph.x.invert(eventX);
60 |
61 | var domainIndexScale = d3.scale.linear()
62 | .domain([data[0].x, data.slice(-1)[0].x])
63 | .range([0, data.length]);
64 |
65 | var approximateIndex = Math.floor(domainIndexScale(domainX));
66 | var dataIndex = Math.min(approximateIndex || 0, data.length - 1);
67 |
68 | for (var i = approximateIndex; i < data.length - 1;) {
69 |
70 | if (!data[i] || !data[i + 1]) break;
71 | if (data[i].x <= domainX && data[i + 1].x > domainX) { dataIndex = i; break }
72 |
73 | if (data[i + 1].x <= domainX) { i++ } else { i-- }
74 | }
75 |
76 | var value = data[dataIndex];
77 |
78 | var distance = Math.sqrt(
79 | Math.pow(Math.abs(graph.x(value.x) - eventX), 2) +
80 | Math.pow(Math.abs(graph.y(value.y + value.y0) - eventY), 2)
81 | );
82 |
83 | var xFormatter = series.xFormatter || this.xFormatter;
84 | var yFormatter = series.yFormatter || this.yFormatter;
85 |
86 | var point = {
87 | formattedXValue: xFormatter(value.x),
88 | formattedYValue: yFormatter(value.y),
89 | series: series,
90 | value: value,
91 | distance: distance,
92 | order: j,
93 | name: series.name
94 | };
95 |
96 | if (!nearestPoint || distance < nearestPoint.distance) {
97 | nearestPoint = point;
98 | }
99 |
100 | points.push(point);
101 |
102 | }, this );
103 |
104 |
105 | nearestPoint.active = true;
106 |
107 | var domainX = nearestPoint.value.x;
108 | var formattedXValue = nearestPoint.formattedXValue;
109 |
110 | this.element.innerHTML = '';
111 | this.element.style.left = graph.x(domainX) + 'px';
112 |
113 | this.visible && this.render( {
114 | points: points,
115 | detail: points, // for backwards compatibility
116 | mouseX: eventX,
117 | mouseY: eventY,
118 | formattedXValue: formattedXValue,
119 | domainX: domainX
120 | } );
121 | },
122 |
123 | hide: function() {
124 | this.visible = false;
125 | this.element.classList.add('inactive');
126 |
127 | if (typeof this.onHide == 'function') {
128 | this.onHide();
129 | }
130 | },
131 |
132 | show: function() {
133 | this.visible = true;
134 | this.element.classList.remove('inactive');
135 |
136 | if (typeof this.onShow == 'function') {
137 | this.onShow();
138 | }
139 | },
140 |
141 | render: function(args) {
142 |
143 | var graph = this.graph;
144 | var points = args.points;
145 | var point = points.filter( function(p) { return p.active } ).shift();
146 |
147 | if (point.value.y === null) return;
148 |
149 | var formattedXValue = this.xFormatter(point.value.x);
150 | var formattedYValue = this.yFormatter(point.value.y);
151 |
152 | this.element.innerHTML = '';
153 | this.element.style.left = graph.x(point.value.x) + 'px';
154 |
155 | var xLabel = document.createElement('div');
156 |
157 | xLabel.className = 'x_label';
158 | xLabel.innerHTML = formattedXValue;
159 | this.element.appendChild(xLabel);
160 |
161 | var item = document.createElement('div');
162 |
163 | item.className = 'item';
164 | item.innerHTML = this.formatter(point.series, point.value.x, point.value.y, formattedXValue, formattedYValue, point);
165 | item.style.top = this.graph.y(point.value.y0 + point.value.y) + 'px';
166 |
167 | this.element.appendChild(item);
168 |
169 | var dot = document.createElement('div');
170 |
171 | dot.className = 'dot';
172 | dot.style.top = item.style.top;
173 | dot.style.borderColor = point.series.color;
174 |
175 | this.element.appendChild(dot);
176 |
177 | if (point.active) {
178 | item.className = 'item active';
179 | dot.className = 'dot active';
180 | }
181 |
182 | this.show();
183 |
184 | if (typeof this.onRender == 'function') {
185 | this.onRender(args);
186 | }
187 | },
188 |
189 | _addListeners: function() {
190 |
191 | this.graph.element.addEventListener(
192 | 'mousemove',
193 | function(e) {
194 | this.visible = true;
195 | this.update(e)
196 | }.bind(this),
197 | false
198 | );
199 |
200 | this.graph.onUpdate( function() { this.update() }.bind(this) );
201 |
202 | this.graph.element.addEventListener(
203 | 'mouseout',
204 | function(e) {
205 | if (e.relatedTarget && !(e.relatedTarget.compareDocumentPosition(this.graph.element) & Node.DOCUMENT_POSITION_CONTAINS)) {
206 | this.hide();
207 | }
208 | }.bind(this),
209 | false
210 | );
211 | }
212 | });
213 |
214 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/examples/data/status.json:
--------------------------------------------------------------------------------
1 | {"1320630300":{"304":41,"206":0,"502":0,"400":2,"408":49,"401":32,"200":1275,"302":13,"500":1,"301":7,"404":1},"1320629640":{"304":42,"206":0,"502":0,"400":2,"408":42,"401":29,"200":1245,"302":10,"500":0,"301":5,"404":0},"1320627540":{"304":55,"502":0,"400":2,"401":22,"408":43,"200":1178,"302":9,"301":8,"404":5},"1320630180":{"403":0,"304":39,"206":0,"502":0,"400":2,"408":39,"401":31,"200":1340,"302":14,"500":1,"404":1,"301":5},"1320628200":{"304":37,"206":0,"502":0,"400":2,"408":47,"401":30,"200":1232,"302":27,"301":8,"404":1},"1320629220":{"304":46,"206":0,"502":0,"400":2,"408":42,"401":29,"200":1212,"302":8,"301":8,"404":0},"1320627360":{"304":30,"206":0,"502":0,"400":1,"408":43,"401":27,"200":1190,"302":10,"500":0,"301":9,"404":1},"1320630120":{"304":44,"206":0,"502":0,"400":2,"408":48,"401":31,"200":1314,"302":11,"500":1,"301":7,"404":0},"1320629280":{"304":28,"206":0,"502":0,"400":2,"401":29,"408":43,"200":1236,"302":9,"500":0,"301":11},"1320628380":{"304":56,"206":0,"502":0,"400":4,"408":44,"401":23,"200":1305,"201":0,"302":16,"301":6,"404":1},"1320630480":{"304":60,"206":0,"502":0,"400":3,"408":51,"401":29,"200":1267,"302":12,"500":0,"301":8,"404":1},"1320628920":{"304":38,"206":0,"502":0,"400":2,"408":35,"401":21,"200":1211,"201":0,"302":9,"301":7,"404":1},"1320628320":{"304":46,"206":0,"502":0,"400":4,"408":43,"401":21,"200":1197,"302":13,"500":0,"301":5,"404":1},"1320629460":{"304":40,"502":1,"400":2,"401":27,"408":46,"200":1179,"302":39,"301":10,"404":1},"1320628500":{"304":40,"206":0,"502":0,"400":5,"408":42,"401":31,"200":1316,"302":10,"301":7,"404":1},"1320627300":{"304":34,"206":0,"502":0,"400":1,"408":48,"401":24,"200":1264,"302":9,"301":7,"404":1},"1320627960":{"403":0,"304":59,"206":0,"502":0,"400":2,"408":38,"401":27,"200":1180,"201":0,"302":7,"409":0,"500":0,"404":0,"301":8},"1320630600":{"304":40,"206":0,"502":0,"400":3,"408":46,"401":28,"200":1297,"302":12,"500":1,"301":7,"404":2},"1320628560":{"304":34,"206":0,"502":0,"400":3,"408":41,"401":31,"200":1275,"302":8,"301":9,"404":1},"1320628080":{"304":31,"206":0,"502":0,"400":2,"408":41,"401":27,"200":1177,"201":0,"302":5,"405":0,"301":7,"404":1},"1320627780":{"304":59,"502":0,"400":3,"401":27,"408":39,"200":1246,"302":14,"301":9,"404":1},"1320629940":{"304":42,"502":0,"400":2,"401":34,"408":44,"200":1297,"302":12,"500":0,"301":4,"404":1},"1320628020":{"304":38,"502":0,"400":3,"408":43,"401":27,"200":1200,"302":6,"405":0,"301":9,"404":0},"1320630360":{"304":44,"206":1,"502":0,"400":1,"408":47,"401":25,"200":1270,"302":11,"500":0,"301":7,"404":1},"1320629760":{"304":40,"206":0,"502":0,"400":2,"408":43,"401":29,"200":1302,"302":9,"500":0,"301":5,"404":1},"1320627720":{"304":36,"502":0,"400":3,"401":24,"408":43,"200":1166,"302":7,"301":9,"404":1},"1320627420":{"304":35,"206":0,"502":0,"400":2,"408":41,"401":28,"200":1220,"302":14,"301":10,"404":1},"1320629340":{"304":41,"206":0,"502":0,"400":3,"408":42,"401":33,"200":1255,"302":39,"301":10,"404":1},"1320628860":{"304":27,"206":0,"502":0,"400":2,"408":39,"401":20,"200":1167,"302":6,"301":7,"404":1},"1320629160":{"403":0,"304":43,"502":0,"400":2,"408":43,"401":23,"200":1214,"302":9,"410":0,"301":7,"404":1},"1320630420":{"304":39,"206":0,"502":0,"400":2,"408":46,"401":31,"200":1318,"302":10,"500":1,"301":9,"404":1},"1320627120":{"304":30,"206":0,"502":0,"400":3,"408":42,"401":29,"200":1166,"302":7,"301":6,"404":0},"1320630000":{"304":35,"502":0,"400":2,"401":29,"408":49,"200":1244,"302":8,"500":0,"301":3,"404":1},"1320629880":{"304":41,"502":0,"400":2,"401":30,"408":45,"200":1282,"302":9,"500":0,"301":5,"404":1},"1320628260":{"304":34,"204":0,"502":0,"400":5,"408":44,"401":28,"200":1205,"201":0,"302":8,"500":0,"301":10,"404":1},"1320629400":{"304":42,"206":0,"502":0,"400":2,"408":43,"401":30,"200":1242,"302":43,"301":10,"404":1},"1320627600":{"304":53,"206":0,"502":0,"400":2,"408":39,"401":26,"200":1190,"302":13,"500":0,"301":8,"404":3},"1320627660":{"304":42,"206":0,"502":1,"400":2,"408":42,"401":25,"200":1199,"201":0,"302":14,"301":7,"404":2},"1320629100":{"304":26,"502":0,"400":2,"401":23,"408":45,"200":1213,"302":9,"500":0,"301":7,"404":2},"1320627900":{"304":48,"502":0,"400":2,"401":26,"408":45,"200":1219,"302":7,"301":9,"404":1},"1320629580":{"304":22,"206":0,"502":0,"400":2,"408":37,"401":27,"200":1184,"302":13,"500":0,"301":8,"404":1},"1320628440":{"304":46,"206":0,"502":0,"400":4,"408":45,"401":27,"200":1320,"201":0,"302":11,"500":0,"301":6,"404":0},"1320628680":{"304":60,"502":0,"400":4,"408":45,"401":29,"200":1269,"201":0,"302":10,"301":9,"404":1},"1320630060":{"304":47,"502":0,"400":2,"401":28,"408":49,"200":1249,"302":8,"500":0,"301":6,"404":1},"1320627840":{"304":55,"502":0,"400":1,"401":23,"408":39,"200":1186,"302":7,"301":9,"404":1},"1320627180":{"304":24,"206":0,"502":0,"400":2,"408":38,"401":26,"200":1163,"302":7,"301":5,"404":1},"1320628740":{"304":50,"206":0,"502":0,"400":4,"408":40,"401":28,"200":1235,"302":10,"500":0,"301":8,"404":1},"1320630540":{"304":47,"206":0,"502":0,"400":4,"408":42,"401":28,"200":1371,"302":12,"500":0,"301":6,"404":1},"1320629040":{"304":29,"206":0,"502":1,"400":3,"408":42,"401":25,"200":1169,"302":7,"500":0,"410":0,"301":7,"404":1},"1320630240":{"403":0,"304":27,"206":0,"502":0,"400":1,"408":51,"401":30,"200":1297,"302":9,"500":0,"404":1,"301":7},"1320627480":{"304":34,"206":0,"502":0,"400":2,"408":40,"401":26,"200":1183,"302":13,"301":10,"404":2},"1320628620":{"304":37,"502":0,"400":5,"401":31,"408":45,"200":1215,"302":9,"301":10,"404":1},"1320628140":{"304":49,"206":0,"502":0,"400":2,"408":40,"401":33,"200":1238,"302":16,"301":8,"404":1},"1320629520":{"304":31,"502":0,"400":2,"401":29,"408":38,"200":1233,"302":32,"301":10,"404":0},"1320627240":{"304":40,"206":0,"502":0,"400":1,"401":23,"408":42,"200":1186,"302":8,"301":6},"1320629700":{"304":45,"206":0,"502":0,"400":1,"408":47,"401":26,"200":1206,"302":7,"500":0,"301":6,"404":1},"1320628980":{"304":38,"502":0,"400":2,"408":42,"401":27,"200":1234,"302":11,"405":0,"301":7,"404":0},"1320628800":{"304":32,"206":0,"502":0,"400":2,"408":50,"401":22,"200":1121,"302":9,"500":0,"301":7,"404":1},"1320629820":{"304":41,"206":0,"502":0,"400":2,"408":40,"401":23,"200":1280,"302":8,"301":5,"404":1}}
--------------------------------------------------------------------------------
/html/scripts/main.js:
--------------------------------------------------------------------------------
1 | var crimeApp;
2 | $(document).ready(function() {
3 | crimeApp = new CrimeApp();
4 | crimeApp.init();
5 | });
6 |
7 |
8 | function CrimeApp() {
9 | //v0.1.6
10 |
11 | var map, mapManager, callTypes, calls;
12 | var mapInitDone, sliderReady, wasPlaying, callsLoaded, typesLoaded;
13 | var firstFrameDate;
14 | var secPerFrame = 600;
15 |
16 | //Public functions
17 |
18 | this.init = function init() {
19 | var mapOptions = {
20 | center: new google.maps.LatLng(43.082, -89.400),
21 | zoom: 11,
22 | mapTypeId: google.maps.MapTypeId.ROADMAP
23 | };
24 |
25 | map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
26 | google.maps.event.addListener(map, 'dragend', onMapDragEnd);
27 |
28 | mapManager = new MapPlayer({
29 | onFrame: onFrame,
30 | fps: 6,
31 | decay: 12,
32 | });
33 |
34 | $.getJSON("scripts/call_types.json", onLoadCallTypes);
35 | $.getJSON("scripts/calls.json", onLoadCalls);
36 | }
37 |
38 | //Private functions
39 |
40 | function roundMinutesDown(time) {
41 | var tDate = new Date(time);
42 | var minutes = tDate.getMinutes();
43 | var minutes = minutes - (minutes % (secPerFrame / 60));
44 | tDate.setMinutes(minutes);
45 | return tDate;
46 | }
47 |
48 | function formatTime(time) {
49 | var fDate = new Date(time);
50 | var niceDateText;
51 | var hours, hourLabel, minutes;
52 |
53 | hours = fDate.getHours();
54 | if (hours < 12) {
55 | hourLabel = "am";
56 | } else {
57 | hourLabel = "pm";
58 | hours -= 12;
59 | }
60 | if (hours == 0) {
61 | hours = 12;
62 | }
63 |
64 | minutes = fDate.getMinutes();
65 | if (minutes.toString().length == 1) {
66 | minutes = "0" + minutes;
67 | }
68 |
69 | niceDateText = fDate.toDateString() + ", ";
70 | niceDateText += hours + ":" + minutes + hourLabel;
71 |
72 | return niceDateText;
73 | }
74 |
75 | function onLoadComplete() {
76 | //Don't turn on the UI until ajax is done.
77 | if (!(typesLoaded && callsLoaded)) {
78 | return;
79 | }
80 |
81 | //Create frames based on data
82 | var i, //each frame
83 | j, //each call per frame
84 | f; //new frame object
85 | for (i = 0; i < calls.length; i++) {
86 | for (j = 0; j < calls[i]['data'].length; j++) {
87 | calls[i]['data'][j].color = callTypes[calls[i]['data'][j]['it']].color;
88 | calls[i]['data'][j].iwContent =
89 | calls[i]['data'][j]['title'] + " " +
90 | "#" + calls[i]['data'][j]['in'] + " " +
91 | callTypes[calls[i]['data'][j]['it']].title;
92 | }
93 | f = new MapFrame({
94 | exData: { title: calls[i]['t'] },
95 | map: map,
96 | data: calls[i]['data']
97 | });
98 | mapManager.pushFrame(f);
99 | }
100 | mapManager.draw();
101 |
102 | firstFrameDate = roundMinutesDown(calls[0]['data'][0]['d']);
103 |
104 | $("#slider").on("slidecreate", function() {
105 | sliderReady = true;
106 | });
107 | $("#slider").on("slidestart", function() {
108 | wasPlaying = mapManager.isPlaying();
109 | mapManager.pause();
110 | });
111 | $("#slider").on("slide", function(event, ui) {
112 | var seekTime = firstFrameDate.getTime();
113 | seekTime += (secPerFrame * ui.value * 1000);
114 | $("#curTime").text(formatTime(seekTime));
115 | });
116 | $("#slider").on("slidestop", function(event, ui) {
117 | jump(ui.value);
118 | if (wasPlaying) {
119 | mapManager.play();
120 | }
121 | });
122 | $("#slider").slider({
123 | min: 0,
124 | max: mapManager.numFrames(),
125 | });
126 |
127 | $("#playToggle").click(btnTogglePlay);
128 | $("#playToggle").removeAttr("disabled");
129 | $("#nextFrame").click(btnNextFrame);
130 | $("#nextFrame").removeAttr("disabled");
131 | //$("#speedUp").on("click", btnSpeedUp);
132 | //$("#speedDown").on("click", btnSpeedDown);
133 |
134 | $("#btnLegend").click(btnLegend);
135 | $("#btnInfo").click(btnInfo);
136 | $("#btnSearch").click(btnSearch);
137 | $("#btnContact").click(btnContact);
138 |
139 | setTimeout(function() {$("#loading").fadeOut(300);}, 1000); //allow 1s for map draw
140 | }
141 |
142 | function onLoadCallTypes(data) {
143 | callTypes = data;
144 | typesLoaded = true;
145 | onLoadComplete();
146 | }
147 |
148 | function onLoadCalls(data) {
149 | calls = data;
150 | callsLoaded = true;
151 | onLoadComplete();
152 | }
153 |
154 | function onMapDragEnd() {
155 | //console.log(map.getCenter().toString());
156 | }
157 |
158 | function onFrame(infos) {
159 | //$("#curTime").text(formatTime(infos.exData.title) + " (" + infos.index + "/" + infos.count + ")");
160 | $("#curTime").text(formatTime(infos.exData.title));
161 | $("#tod").tod({date: String(infos.exData.title)});
162 | if (sliderReady === true) {
163 | $("#slider").slider("option", "value", infos.index);
164 | }
165 | }
166 |
167 | function jump(i) {
168 | mapManager.jump(i);
169 | mapManager.draw();
170 | }
171 |
172 | function btnLegend() {
173 | //mapManager.pause();
174 | $("#legendDialog").dialog({
175 | title: "Legend",
176 | //modal: true,
177 | width: 500,
178 | resizable: false,
179 | });
180 | }
181 |
182 | function btnInfo() {
183 | mapManager.pause();
184 | $("#infoDialog").dialog({
185 | title: "Info",
186 | modal: true,
187 | width: 500,
188 | resizable: false,
189 | });
190 | }
191 |
192 | function btnSearch() {
193 | mapManager.pause();
194 | $("#searchDialog").dialog({
195 | title: "Search",
196 | modal: true,
197 | width: 500,
198 | resizable: false,
199 | });
200 | }
201 |
202 | function btnContact() {
203 | mapManager.pause();
204 | $("#contactDialog").dialog({
205 | title: "Contact",
206 | modal: true,
207 | width: 500,
208 | resizable: false,
209 | });
210 | }
211 |
212 | function btnNextFrame() {
213 | console.log("main.nextFrame()");
214 | mapManager.drawNext();
215 | }
216 |
217 | function btnTogglePlay() {
218 | mapManager.togglePlay();
219 | if (mapManager.isPlaying()) {
220 | $("#playToggle").val("Pause");
221 | $("#nextFrame").attr("disabled","disabled");
222 | } else {
223 | $("#playToggle").val("Play");
224 | $("#nextFrame").removeAttr("disabled");
225 | }
226 |
227 | }
228 |
229 | function btnSpeedUp() {
230 | //TODO
231 | console.log("speed up");
232 | }
233 |
234 | function btnSpeedDown() {
235 | //TODO
236 | console.log("speed down");
237 | }
238 | }
239 |
240 |
241 |
--------------------------------------------------------------------------------
/html/scripts/rickshaw/src/js/Rickshaw.Graph.js:
--------------------------------------------------------------------------------
1 | Rickshaw.namespace('Rickshaw.Graph');
2 |
3 | Rickshaw.Graph = function(args) {
4 |
5 | if (!args.element) throw "Rickshaw.Graph needs a reference to an element";
6 |
7 | this.element = args.element;
8 | this.series = args.series;
9 |
10 | this.defaults = {
11 | interpolation: 'cardinal',
12 | offset: 'zero',
13 | min: undefined,
14 | max: undefined
15 | };
16 |
17 | Rickshaw.keys(this.defaults).forEach( function(k) {
18 | this[k] = args[k] || this.defaults[k];
19 | }, this );
20 |
21 | this.window = {};
22 |
23 | this.updateCallbacks = [];
24 |
25 | var self = this;
26 |
27 | this.initialize = function(args) {
28 |
29 | this.validateSeries(args.series);
30 |
31 | this.series.active = function() { return self.series.filter( function(s) { return !s.disabled } ) };
32 |
33 | this.setSize({ width: args.width, height: args.height });
34 |
35 | this.element.classList.add('rickshaw_graph');
36 | this.vis = d3.select(this.element)
37 | .append("svg:svg")
38 | .attr('width', this.width)
39 | .attr('height', this.height);
40 |
41 | var renderers = [
42 | Rickshaw.Graph.Renderer.Stack,
43 | Rickshaw.Graph.Renderer.Line,
44 | Rickshaw.Graph.Renderer.Bar,
45 | Rickshaw.Graph.Renderer.Area,
46 | Rickshaw.Graph.Renderer.ScatterPlot
47 | ];
48 |
49 | renderers.forEach( function(r) {
50 | if (!r) return;
51 | self.registerRenderer(new r( { graph: self } ));
52 | } );
53 |
54 | this.setRenderer(args.renderer || 'stack', args);
55 | this.discoverRange();
56 | };
57 |
58 | this.validateSeries = function(series) {
59 |
60 | if (!(series instanceof Array) && !(series instanceof Rickshaw.Series)) {
61 | var seriesSignature = Object.prototype.toString.apply(series);
62 | throw "series is not an array: " + seriesSignature;
63 | }
64 |
65 | var pointsCount;
66 |
67 | series.forEach( function(s) {
68 |
69 | if (!(s instanceof Object)) {
70 | throw "series element is not an object: " + s;
71 | }
72 | if (!(s.data)) {
73 | throw "series has no data: " + JSON.stringify(s);
74 | }
75 | if (!(s.data instanceof Array)) {
76 | throw "series data is not an array: " + JSON.stringify(s.data);
77 | }
78 |
79 | var x = s.data[0].x;
80 | var y = s.data[0].y;
81 |
82 | if (typeof x != 'number' || ( typeof y != 'number' && y !== null ) ) {
83 | throw "x and y properties of points should be numbers instead of " +
84 | (typeof x) + " and " + (typeof y)
85 | }
86 |
87 | }, this );
88 | };
89 |
90 | this.dataDomain = function() {
91 |
92 | // take from the first series
93 | var data = this.series[0].data;
94 |
95 | return [ data[0].x, data.slice(-1).shift().x ];
96 |
97 | };
98 |
99 | this.discoverRange = function() {
100 |
101 | var domain = this.renderer.domain();
102 |
103 | this.x = d3.scale.linear().domain(domain.x).range([0, this.width]);
104 |
105 | this.y = d3.scale.linear().domain(domain.y).range([this.height, 0]);
106 |
107 | this.y.magnitude = d3.scale.linear()
108 | .domain([domain.y[0] - domain.y[0], domain.y[1] - domain.y[0]])
109 | .range([0, this.height]);
110 | };
111 |
112 | this.render = function() {
113 |
114 | var stackedData = this.stackData();
115 | this.discoverRange();
116 |
117 | this.renderer.render();
118 |
119 | this.updateCallbacks.forEach( function(callback) {
120 | callback();
121 | } );
122 | };
123 |
124 | this.update = this.render;
125 |
126 | this.stackData = function() {
127 |
128 | var data = this.series.active()
129 | .map( function(d) { return d.data } )
130 | .map( function(d) { return d.filter( function(d) { return this._slice(d) }, this ) }, this);
131 |
132 | this.stackData.hooks.data.forEach( function(entry) {
133 | data = entry.f.apply(self, [data]);
134 | } );
135 |
136 | var stackedData;
137 |
138 | if (!this.renderer.unstack) {
139 |
140 | this._validateStackable();
141 |
142 | var layout = d3.layout.stack();
143 | layout.offset( self.offset );
144 | stackedData = layout(data);
145 | }
146 |
147 | stackedData = stackedData || data;
148 |
149 | this.stackData.hooks.after.forEach( function(entry) {
150 | stackedData = entry.f.apply(self, [data]);
151 | } );
152 |
153 | var i = 0;
154 | this.series.forEach( function(series) {
155 | if (series.disabled) return;
156 | series.stack = stackedData[i++];
157 | } );
158 |
159 | this.stackedData = stackedData;
160 | return stackedData;
161 | };
162 |
163 | this._validateStackable = function() {
164 |
165 | var series = this.series;
166 | var pointsCount;
167 |
168 | series.forEach( function(s) {
169 |
170 | pointsCount = pointsCount || s.data.length;
171 |
172 | if (pointsCount && s.data.length != pointsCount) {
173 | throw "stacked series cannot have differing numbers of points: " +
174 | pointsCount + " vs " + s.data.length + "; see Rickshaw.Series.fill()";
175 | }
176 |
177 | }, this );
178 | };
179 |
180 | this.stackData.hooks = { data: [], after: [] };
181 |
182 | this._slice = function(d) {
183 |
184 | if (this.window.xMin || this.window.xMax) {
185 |
186 | var isInRange = true;
187 |
188 | if (this.window.xMin && d.x < this.window.xMin) isInRange = false;
189 | if (this.window.xMax && d.x > this.window.xMax) isInRange = false;
190 |
191 | return isInRange;
192 | }
193 |
194 | return true;
195 | };
196 |
197 | this.onUpdate = function(callback) {
198 | this.updateCallbacks.push(callback);
199 | };
200 |
201 | this.registerRenderer = function(renderer) {
202 | this._renderers = this._renderers || {};
203 | this._renderers[renderer.name] = renderer;
204 | };
205 |
206 | this.configure = function(args) {
207 |
208 | if (args.width || args.height) {
209 | this.setSize(args);
210 | }
211 |
212 | Rickshaw.keys(this.defaults).forEach( function(k) {
213 | this[k] = k in args ? args[k]
214 | : k in this ? this[k]
215 | : this.defaults[k];
216 | }, this );
217 |
218 | this.setRenderer(args.renderer || this.renderer.name, args);
219 | };
220 |
221 | this.setRenderer = function(name, args) {
222 |
223 | if (!this._renderers[name]) {
224 | throw "couldn't find renderer " + name;
225 | }
226 | this.renderer = this._renderers[name];
227 |
228 | if (typeof args == 'object') {
229 | this.renderer.configure(args);
230 | }
231 | };
232 |
233 | this.setSize = function(args) {
234 |
235 | args = args || {};
236 |
237 | if (typeof window !== undefined) {
238 | var style = window.getComputedStyle(this.element, null);
239 | var elementWidth = parseInt(style.getPropertyValue('width'));
240 | var elementHeight = parseInt(style.getPropertyValue('height'));
241 | }
242 |
243 | this.width = args.width || elementWidth || 400;
244 | this.height = args.height || elementHeight || 250;
245 |
246 | this.vis && this.vis
247 | .attr('width', this.width)
248 | .attr('height', this.height);
249 | }
250 |
251 | this.initialize(args);
252 | };
253 |
--------------------------------------------------------------------------------