pulse_meter_visualizer 0.4.11
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rbenv-version +1 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/Procfile +3 -0
- data/README.md +40 -0
- data/Rakefile +72 -0
- data/examples/basic.ru +145 -0
- data/examples/basic_sensor_data.rb +96 -0
- data/lib/pulse_meter/visualize/app.rb +78 -0
- data/lib/pulse_meter/visualize/base.rb +15 -0
- data/lib/pulse_meter/visualize/coffee/application.coffee +40 -0
- data/lib/pulse_meter/visualize/coffee/collections/page_info_list.coffee +17 -0
- data/lib/pulse_meter/visualize/coffee/collections/sensor_info_list.coffee +4 -0
- data/lib/pulse_meter/visualize/coffee/collections/widget_list.coffee +14 -0
- data/lib/pulse_meter/visualize/coffee/extensions.coffee +26 -0
- data/lib/pulse_meter/visualize/coffee/models/dinamic_widget.coffee +34 -0
- data/lib/pulse_meter/visualize/coffee/models/page_info.coffee +2 -0
- data/lib/pulse_meter/visualize/coffee/models/sensor_info.coffee +2 -0
- data/lib/pulse_meter/visualize/coffee/models/widget.coffee +54 -0
- data/lib/pulse_meter/visualize/coffee/presenters/area.coffee +2 -0
- data/lib/pulse_meter/visualize/coffee/presenters/gauge.coffee +11 -0
- data/lib/pulse_meter/visualize/coffee/presenters/line.coffee +2 -0
- data/lib/pulse_meter/visualize/coffee/presenters/pie.coffee +20 -0
- data/lib/pulse_meter/visualize/coffee/presenters/series.coffee +44 -0
- data/lib/pulse_meter/visualize/coffee/presenters/table.coffee +10 -0
- data/lib/pulse_meter/visualize/coffee/presenters/timeline.coffee +13 -0
- data/lib/pulse_meter/visualize/coffee/presenters/widget.coffee +65 -0
- data/lib/pulse_meter/visualize/coffee/router.coffee +21 -0
- data/lib/pulse_meter/visualize/coffee/views/dynamic_chart.coffee +91 -0
- data/lib/pulse_meter/visualize/coffee/views/dynamic_widget.coffee +58 -0
- data/lib/pulse_meter/visualize/coffee/views/page_title.coffee +17 -0
- data/lib/pulse_meter/visualize/coffee/views/page_titles.coffee +15 -0
- data/lib/pulse_meter/visualize/coffee/views/sensor_info_list.coffee +19 -0
- data/lib/pulse_meter/visualize/coffee/views/widget.coffee +99 -0
- data/lib/pulse_meter/visualize/coffee/views/widget_chart.coffee +13 -0
- data/lib/pulse_meter/visualize/coffee/views/widget_list.coffee +15 -0
- data/lib/pulse_meter/visualize/dsl/base.rb +131 -0
- data/lib/pulse_meter/visualize/dsl/errors.rb +40 -0
- data/lib/pulse_meter/visualize/dsl/layout.rb +27 -0
- data/lib/pulse_meter/visualize/dsl/page.rb +33 -0
- data/lib/pulse_meter/visualize/dsl/sensor.rb +20 -0
- data/lib/pulse_meter/visualize/dsl/widget.rb +37 -0
- data/lib/pulse_meter/visualize/dsl/widgets/area.rb +20 -0
- data/lib/pulse_meter/visualize/dsl/widgets/gauge.rb +12 -0
- data/lib/pulse_meter/visualize/dsl/widgets/line.rb +21 -0
- data/lib/pulse_meter/visualize/dsl/widgets/pie.rb +16 -0
- data/lib/pulse_meter/visualize/dsl/widgets/table.rb +19 -0
- data/lib/pulse_meter/visualize/layout.rb +79 -0
- data/lib/pulse_meter/visualize/page.rb +25 -0
- data/lib/pulse_meter/visualize/public/css/application.css +56 -0
- data/lib/pulse_meter/visualize/public/css/bootstrap.css +4883 -0
- data/lib/pulse_meter/visualize/public/css/bootstrap.min.css +729 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/pulse_meter/visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
- data/lib/pulse_meter/visualize/public/css/jquery-ui-1.8.16.bootstrap.css +1320 -0
- data/lib/pulse_meter/visualize/public/favicon.ico +208 -0
- data/lib/pulse_meter/visualize/public/img/glyphicons-halflings-white.png +0 -0
- data/lib/pulse_meter/visualize/public/img/glyphicons-halflings.png +0 -0
- data/lib/pulse_meter/visualize/public/js/application.js +973 -0
- data/lib/pulse_meter/visualize/public/js/backbone-min.js +38 -0
- data/lib/pulse_meter/visualize/public/js/bootstrap.js +1835 -0
- data/lib/pulse_meter/visualize/public/js/jquery-1.7.2.min.js +4 -0
- data/lib/pulse_meter/visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +791 -0
- data/lib/pulse_meter/visualize/public/js/jquery-ui-1.8.23.custom.min.js +21 -0
- data/lib/pulse_meter/visualize/public/js/jquery-ui-timepicker-addon.js +1687 -0
- data/lib/pulse_meter/visualize/public/js/json2.js +487 -0
- data/lib/pulse_meter/visualize/public/js/underscore-min.js +32 -0
- data/lib/pulse_meter/visualize/sensor.rb +63 -0
- data/lib/pulse_meter/visualize/series_extractor.rb +107 -0
- data/lib/pulse_meter/visualize/views/main.haml +30 -0
- data/lib/pulse_meter/visualize/views/sensors.haml +76 -0
- data/lib/pulse_meter/visualize/views/widgets/area.haml +53 -0
- data/lib/pulse_meter/visualize/views/widgets/extend_options.haml +11 -0
- data/lib/pulse_meter/visualize/views/widgets/gauge.haml +13 -0
- data/lib/pulse_meter/visualize/views/widgets/line.haml +54 -0
- data/lib/pulse_meter/visualize/views/widgets/pie.haml +13 -0
- data/lib/pulse_meter/visualize/views/widgets/table.haml +45 -0
- data/lib/pulse_meter/visualize/widget.rb +38 -0
- data/lib/pulse_meter/visualize/widgets/gauge.rb +47 -0
- data/lib/pulse_meter/visualize/widgets/pie.rb +36 -0
- data/lib/pulse_meter/visualize/widgets/timeline.rb +114 -0
- data/lib/pulse_meter/visualizer.rb +38 -0
- data/lib/pulse_meter_visualizer.rb +2 -0
- data/pulse_meter_visualizer.gemspec +41 -0
- data/spec/pulse_meter/visualize/app_spec.rb +27 -0
- data/spec/pulse_meter/visualize/dsl/layout_spec.rb +64 -0
- data/spec/pulse_meter/visualize/dsl/page_spec.rb +62 -0
- data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +30 -0
- data/spec/pulse_meter/visualize/dsl/widget_spec.rb +6 -0
- data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +44 -0
- data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +22 -0
- data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +44 -0
- data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +35 -0
- data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +36 -0
- data/spec/pulse_meter/visualize/layout_spec.rb +54 -0
- data/spec/pulse_meter/visualize/page_spec.rb +153 -0
- data/spec/pulse_meter/visualize/sensor_spec.rb +120 -0
- data/spec/pulse_meter/visualize/series_extractor_spec.rb +80 -0
- data/spec/pulse_meter/visualize/widgets/area_spec.rb +6 -0
- data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +63 -0
- data/spec/pulse_meter/visualize/widgets/line_spec.rb +6 -0
- data/spec/pulse_meter/visualize/widgets/pie_spec.rb +73 -0
- data/spec/pulse_meter/visualize/widgets/table_spec.rb +6 -0
- data/spec/pulse_meter/visualizer_spec.rb +42 -0
- data/spec/shared_examples/dsl_widget.rb +106 -0
- data/spec/shared_examples/widget.rb +97 -0
- data/spec/spec_helper.rb +36 -0
- metadata +518 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
|
5
|
+
<!-- META -->
|
6
|
+
<meta charset="utf-8">
|
7
|
+
<meta content="en" name="language">
|
8
|
+
<meta name="description" content="Free Online Icons Converter - Convert PNG to ICO and ICO to PNG files : Win 7 & Windows Vista compatible icons">
|
9
|
+
<meta name="keywords" content="convert, png, ico, free, freeware, vista, icons, ico">
|
10
|
+
<meta content="follow, index, all" name="robots">
|
11
|
+
|
12
|
+
|
13
|
+
<!-- TITLE -->
|
14
|
+
<title>ConvertICO.com - Convert .PNG format files to .ICO or .ICO format files to .PNG : Windows 7 compatible icons</title>
|
15
|
+
|
16
|
+
<!-- CSS -->
|
17
|
+
<link href="styles/base.css" rel="stylesheet" type="text/css" >
|
18
|
+
<!--[if IE 7]> <link href="styles/ie7.css" rel="stylesheet" type="text/css" > <![endif]-->
|
19
|
+
<!--[if IE 8]> <link href="styles/ie8.css" rel="stylesheet" type="text/css" > <![endif]-->
|
20
|
+
<!--[if IE 9]> <link href="styles/ie9.css" rel="stylesheet" type="text/css" > <![endif]-->
|
21
|
+
|
22
|
+
<!-- FAVICON -->
|
23
|
+
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" >
|
24
|
+
|
25
|
+
<!-- TYPEKIT -->
|
26
|
+
<script type="text/javascript" src="http://use.typekit.com/jws7edv.js"></script>
|
27
|
+
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
|
28
|
+
|
29
|
+
<!-- JS -->
|
30
|
+
<script type="text/javascript" src="scripts/jquery.js"></script>
|
31
|
+
<script type="text/javascript" src="scripts/jquery.imagesloaded.js"></script>
|
32
|
+
<script type="text/javascript" src="scripts/jquery.form.js"></script>
|
33
|
+
<script type="text/javascript" src="scripts/spin.min.js"></script>
|
34
|
+
<script type="text/javascript" src="scripts/modernizr.js"></script>
|
35
|
+
<script type="text/javascript" src="scripts/ba-debug.min.js"></script>
|
36
|
+
<script type="text/javascript" src="scripts/main.js"></script>
|
37
|
+
<!--[if IE]> <style type="text/css">img { behavior: url(scripts/iepngfix.htc) }</style> <![endif]-->
|
38
|
+
|
39
|
+
</head>
|
40
|
+
|
41
|
+
<body>
|
42
|
+
<!-- BuySellAds.com Ad Code -->
|
43
|
+
<script type="text/javascript">
|
44
|
+
(function(){
|
45
|
+
var bsa = document.createElement('script');
|
46
|
+
bsa.type = 'text/javascript';
|
47
|
+
bsa.async = true;
|
48
|
+
bsa.src = 'http://s3.buysellads.com/ac/bsa.js';
|
49
|
+
(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
|
50
|
+
})();
|
51
|
+
</script>
|
52
|
+
|
53
|
+
<div id="top">
|
54
|
+
<div class="container">
|
55
|
+
<ul id="network">
|
56
|
+
<li class="parent">proIcons Network</li>
|
57
|
+
<li><a href="http://www.proicons.com">proIcons.com</a></li>
|
58
|
+
<li><a href="http://www.windowsico.com">WindowsICO.com</a></li>
|
59
|
+
<li class="selected"><a href="http://www.convertico.com">ConvertICO.com</a></li>
|
60
|
+
<li><a href="http://www.favico.com">FavICO.com</a></li>
|
61
|
+
</ul><!-- #network -->
|
62
|
+
|
63
|
+
<div id="counter">
|
64
|
+
<p><span class="total">6,088,770</span> Icons Converted
|
65
|
+
<span class="hour">1,163</span> In The Last Hour</p>
|
66
|
+
</div><!-- #counter -->
|
67
|
+
</div><!-- .container -->
|
68
|
+
</div><!-- #top -->
|
69
|
+
|
70
|
+
<div id="main">
|
71
|
+
<div class="container">
|
72
|
+
<div class="lcol">
|
73
|
+
|
74
|
+
<div id="intro">
|
75
|
+
<h2><a href="" id="logo">CI</a> ConvertIco</h2>
|
76
|
+
<h3>PNG to ICO / ICO to PNG Conversion</h3>
|
77
|
+
<p><strong>ConvertICO</strong> is a <strong>Free Online ICO/PNG File Converter</strong>.
|
78
|
+
It is fast, free and easy to use. It is used to convert Desktop Icons, App Icons as well as the much needed favicons for websites. Go ahead and give it a try, you will be pleased. <a class="expand" href="#instructions">Click Here for Instructions</a></p>
|
79
|
+
<div class="how">
|
80
|
+
<p>How to Convert Files:</p>
|
81
|
+
<ol>
|
82
|
+
<li>To convert a file located on a webserver: just enter the URL<br> For example: http://google.com/filename.png and click the GO button.</li>
|
83
|
+
<li>To convert a file located on your computer: click Browse, locate the file on your computer and then click the GO button.</li>
|
84
|
+
</ol>
|
85
|
+
</div><!-- .how -->
|
86
|
+
</div><!-- #intro -->
|
87
|
+
<script type="text/javascript"><!--
|
88
|
+
google_ad_client = "ca-pub-7595495923317249";
|
89
|
+
/* ConvertICO 468x60 */
|
90
|
+
google_ad_slot = "1090461791";
|
91
|
+
google_ad_width = 468;
|
92
|
+
google_ad_height = 60;
|
93
|
+
//-->
|
94
|
+
</script>
|
95
|
+
<script type="text/javascript"
|
96
|
+
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
97
|
+
</script>
|
98
|
+
<div id="convert">
|
99
|
+
<form name="myform" id="fConvert" action="appleJax.php" method="post" enctype="multipart/form-data">
|
100
|
+
<div class="col1-2">
|
101
|
+
<div class="url">
|
102
|
+
<label>Select File From URL</label>
|
103
|
+
<input name="remoteimgfile" type="text" class="text" value="http://">
|
104
|
+
</div><!-- .url -->
|
105
|
+
|
106
|
+
<div class="file">
|
107
|
+
<label>Select File From Your Computer</label>
|
108
|
+
<input name="imgfile" class="file" type="file" size="59">
|
109
|
+
<input class="fakefile" name="" type="text" value="">
|
110
|
+
<div class="browse">Browse</div>
|
111
|
+
</div>
|
112
|
+
<!-- .file -->
|
113
|
+
</div><!-- .col1-2 -->
|
114
|
+
|
115
|
+
<div class="col2-2">
|
116
|
+
<div id="subContain" class="action">
|
117
|
+
<input class="submit" name="" type="submit" value="GO">
|
118
|
+
</div>
|
119
|
+
<!-- .action -->
|
120
|
+
</div><!-- .col2-2 -->
|
121
|
+
<input id="selected" name="selected" type="hidden">
|
122
|
+
</form>
|
123
|
+
|
124
|
+
<div id="recent">
|
125
|
+
<h4>Recently Converted</h4>
|
126
|
+
<div id="recentView">
|
127
|
+
<ul class="iconslist">
|
128
|
+
<li><img src="/images/1341004889.56/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004888.57/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004888.42/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004883.7/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004875.68/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004873.53/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004866.37/_previmg.png" alt='The latest Converted Icons'/></li><li><img src="/images/1341004861.66/_previmg.png" alt='The latest Converted Icons'/></li> </ul>
|
129
|
+
</div>
|
130
|
+
</div><!-- #recent -->
|
131
|
+
</div><!-- #convert -->
|
132
|
+
|
133
|
+
</div><!-- .lcol -->
|
134
|
+
|
135
|
+
<div class="rcol">
|
136
|
+
<div id="ads">
|
137
|
+
<div class="wrap">
|
138
|
+
<script type="text/javascript"><!--
|
139
|
+
google_ad_client = "ca-pub-7595495923317249";
|
140
|
+
/* 336x280, created 4/6/11 */
|
141
|
+
google_ad_slot = "9617101975";
|
142
|
+
google_ad_width = 336;
|
143
|
+
google_ad_height = 280;
|
144
|
+
//-->
|
145
|
+
</script>
|
146
|
+
<script type="text/javascript"
|
147
|
+
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
148
|
+
</script>
|
149
|
+
</div><!-- .wrap -->
|
150
|
+
</div><!-- #ads -->
|
151
|
+
|
152
|
+
<div id="results">
|
153
|
+
|
154
|
+
<div id="noicons">
|
155
|
+
<h5>Start Converting Icons Now</h5>
|
156
|
+
<p>Icons will appear here once you convert them</p>
|
157
|
+
</div><!-- #noicons -->
|
158
|
+
|
159
|
+
<!-- BuySellAds.com Zone Code -->
|
160
|
+
<div id="bsap_1270400" class="bsarocks bsap_3efb91f3af086a588acca7a4eff4e700"></div>
|
161
|
+
<!-- End BuySellAds.com Zone Code -->
|
162
|
+
</div><!-- #results -->
|
163
|
+
|
164
|
+
</div><!-- .rcol -->
|
165
|
+
|
166
|
+
</div><!-- .container -->
|
167
|
+
</div><!-- #main -->
|
168
|
+
|
169
|
+
|
170
|
+
<div id="footer">
|
171
|
+
<div class="container">
|
172
|
+
<div class="col3">
|
173
|
+
<h4>About</h4>
|
174
|
+
<p>ConvertICO was created by the proIcons.com team to help designers around the world have an easier time converting their icons from <b>png to ico</b> and viceversa. Stay tuned for updates and new features!</p>
|
175
|
+
</div><!-- .col3 -->
|
176
|
+
<div class="col3 mid">
|
177
|
+
<h4>Privacy Statement</h4>
|
178
|
+
<p>This website does not gather any personal info, computer specs or IP. However, your icons are stored publicly. If you do not wish your items to be stored publicly, do not use this website.</p>
|
179
|
+
</div><!-- .col3 -->
|
180
|
+
<div class="col3">
|
181
|
+
<h4>Terms of Use</h4>
|
182
|
+
<p>By using this website to convert your icons, you acknowledge that we are in no way responsible for data error, losses or discrepancies in the conversion. You use the software at your own risk.</p>
|
183
|
+
</div><!-- .col3 -->
|
184
|
+
<div id="copy">
|
185
|
+
<p class="feedback">For <strong>Feedback</strong>, <strong>Suggestions</strong> and <strong>Errors</strong>, write to <em>info at proicons dot com</em></p>
|
186
|
+
<p>© 2008-2012 ConvertICO.COM, a creation and property of the proIcons.com network. All rights reserved.</p>
|
187
|
+
</div><!-- #copy -->
|
188
|
+
|
189
|
+
</div><!-- .container -->
|
190
|
+
</div><!-- #footer -->
|
191
|
+
|
192
|
+
|
193
|
+
<script type="text/javascript">
|
194
|
+
|
195
|
+
var _gaq = _gaq || [];
|
196
|
+
_gaq.push(['_setAccount', 'UA-320719-8']);
|
197
|
+
_gaq.push(['_trackPageview']);
|
198
|
+
|
199
|
+
(function() {
|
200
|
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
201
|
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
202
|
+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
203
|
+
})();
|
204
|
+
|
205
|
+
</script>
|
206
|
+
</body>
|
207
|
+
</html>
|
208
|
+
|
Binary file
|
Binary file
|
@@ -0,0 +1,973 @@
|
|
1
|
+
|
2
|
+
String.prototype.capitalize = function() {
|
3
|
+
return this.charAt(0).toUpperCase() + this.slice(1);
|
4
|
+
};
|
5
|
+
|
6
|
+
String.prototype.strip = function() {
|
7
|
+
if (String.prototype.trim != null) {
|
8
|
+
return this.trim();
|
9
|
+
} else {
|
10
|
+
return this.replace(/^\s+|\s+$/g, "");
|
11
|
+
}
|
12
|
+
};
|
13
|
+
|
14
|
+
Number.prototype.humanize = function() {
|
15
|
+
var d, h, interval, m, res, s;
|
16
|
+
interval = this;
|
17
|
+
res = "";
|
18
|
+
s = interval % 60;
|
19
|
+
if (s > 0) {
|
20
|
+
res = "" + s + " s";
|
21
|
+
}
|
22
|
+
interval = (interval - s) / 60;
|
23
|
+
if (!(interval > 0)) {
|
24
|
+
return res;
|
25
|
+
}
|
26
|
+
m = interval % 60;
|
27
|
+
if (m > 0) {
|
28
|
+
res = ("" + m + " m " + res).strip();
|
29
|
+
}
|
30
|
+
interval = (interval - m) / 60;
|
31
|
+
if (!(interval > 0)) {
|
32
|
+
return res;
|
33
|
+
}
|
34
|
+
h = interval % 24;
|
35
|
+
if (h > 0) {
|
36
|
+
res = ("" + h + " h " + res).strip();
|
37
|
+
}
|
38
|
+
d = (interval - h) / 24;
|
39
|
+
if (d > 0) {
|
40
|
+
return ("" + d + " d " + res).strip();
|
41
|
+
} else {
|
42
|
+
return res;
|
43
|
+
}
|
44
|
+
};
|
45
|
+
var PageInfo;
|
46
|
+
|
47
|
+
PageInfo = Backbone.Model.extend({});
|
48
|
+
var Widget;
|
49
|
+
|
50
|
+
Widget = Backbone.Model.extend({
|
51
|
+
initialize: function() {
|
52
|
+
this.needRefresh = true;
|
53
|
+
this.setNextFetch();
|
54
|
+
return this.timespanInc = 0;
|
55
|
+
},
|
56
|
+
setStartTime: function(startTime) {
|
57
|
+
this.startTime = startTime;
|
58
|
+
},
|
59
|
+
setEndTime: function(endTime) {
|
60
|
+
this.endTime = endTime;
|
61
|
+
},
|
62
|
+
increaseTimespan: function(inc) {
|
63
|
+
this.timespanInc = this.timespanInc + inc;
|
64
|
+
return this.forceUpdate();
|
65
|
+
},
|
66
|
+
resetTimespan: function() {
|
67
|
+
this.timespanInc = 0;
|
68
|
+
this.startTime = null;
|
69
|
+
this.endTime = null;
|
70
|
+
return this.forceUpdate();
|
71
|
+
},
|
72
|
+
timespan: function() {
|
73
|
+
return this.get('timespan') + this.timespanInc;
|
74
|
+
},
|
75
|
+
url: function() {
|
76
|
+
var timespan, url;
|
77
|
+
timespan = this.timespan();
|
78
|
+
url = "" + (this.collection.url()) + "/" + (this.get('id')) + "?";
|
79
|
+
if (!_.isNaN(timespan)) {
|
80
|
+
url += "×pan=" + timespan;
|
81
|
+
}
|
82
|
+
if (this.startTime) {
|
83
|
+
url += "&startTime=" + this.startTime;
|
84
|
+
}
|
85
|
+
if (this.endTime) {
|
86
|
+
url += "&endTime=" + this.endTime;
|
87
|
+
}
|
88
|
+
return url;
|
89
|
+
},
|
90
|
+
time: function() {
|
91
|
+
return (new Date()).getTime();
|
92
|
+
},
|
93
|
+
setNextFetch: function() {
|
94
|
+
return this.nextFetch = this.time() + this.get('redrawInterval') * 1000;
|
95
|
+
},
|
96
|
+
setRefresh: function(needRefresh) {
|
97
|
+
return this.needRefresh = needRefresh;
|
98
|
+
},
|
99
|
+
needFetch: function() {
|
100
|
+
var interval;
|
101
|
+
interval = this.get('redrawInterval');
|
102
|
+
return this.time() > this.nextFetch && this.needRefresh && (interval != null) && interval > 0;
|
103
|
+
},
|
104
|
+
refetch: function() {
|
105
|
+
if (this.needFetch()) {
|
106
|
+
this.forceUpdate();
|
107
|
+
return this.setNextFetch();
|
108
|
+
}
|
109
|
+
},
|
110
|
+
forceUpdate: function() {
|
111
|
+
return this.fetch({
|
112
|
+
success: function(model, response) {
|
113
|
+
return model.trigger('redraw');
|
114
|
+
}
|
115
|
+
});
|
116
|
+
}
|
117
|
+
});
|
118
|
+
var DynamicWidget;
|
119
|
+
|
120
|
+
DynamicWidget = Backbone.Model.extend({
|
121
|
+
setStartTime: function(startTime) {
|
122
|
+
this.startTime = startTime;
|
123
|
+
},
|
124
|
+
setEndTime: function(endTime) {
|
125
|
+
this.endTime = endTime;
|
126
|
+
},
|
127
|
+
increaseTimespan: function(inc) {
|
128
|
+
return this.set('timespan', this.timespan() + inc);
|
129
|
+
},
|
130
|
+
resetTimespan: function() {
|
131
|
+
this.startTime = null;
|
132
|
+
this.endTime = null;
|
133
|
+
return this.set('timespan', null);
|
134
|
+
},
|
135
|
+
timespan: function() {
|
136
|
+
return this.get('timespan');
|
137
|
+
},
|
138
|
+
sensorArgs: function() {
|
139
|
+
return _.map(this.get('sensorIds'), function(name) {
|
140
|
+
return "sensor[]=" + name;
|
141
|
+
}).join('&');
|
142
|
+
},
|
143
|
+
url: function() {
|
144
|
+
var timespan, url;
|
145
|
+
timespan = this.timespan();
|
146
|
+
url = "" + ROOT + "dynamic_widget?" + (this.sensorArgs()) + "&type=" + (this.get('type'));
|
147
|
+
if ((timespan != null) && !_.isNaN(timespan)) {
|
148
|
+
url += "×pan=" + timespan;
|
149
|
+
}
|
150
|
+
if (this.startTime) {
|
151
|
+
url += "&startTime=" + this.startTime;
|
152
|
+
}
|
153
|
+
if (this.endTime) {
|
154
|
+
url += "&endTime=" + this.endTime;
|
155
|
+
}
|
156
|
+
return url;
|
157
|
+
},
|
158
|
+
forceUpdate: function() {
|
159
|
+
return this.fetch({
|
160
|
+
success: function(model, response) {
|
161
|
+
return model.trigger('redraw');
|
162
|
+
}
|
163
|
+
});
|
164
|
+
}
|
165
|
+
});
|
166
|
+
var SensorInfo;
|
167
|
+
|
168
|
+
SensorInfo = Backbone.Model.extend({});
|
169
|
+
var PageInfoList;
|
170
|
+
|
171
|
+
PageInfoList = Backbone.Collection.extend({
|
172
|
+
model: PageInfo,
|
173
|
+
selected: function() {
|
174
|
+
return this.find(function(m) {
|
175
|
+
return m.get('selected');
|
176
|
+
});
|
177
|
+
},
|
178
|
+
selectFirst: function() {
|
179
|
+
if (this.length > 0) {
|
180
|
+
return this.at(0).set('selected', true);
|
181
|
+
}
|
182
|
+
},
|
183
|
+
selectNone: function() {
|
184
|
+
return this.each(function(m) {
|
185
|
+
return m.set('selected', false);
|
186
|
+
});
|
187
|
+
},
|
188
|
+
selectPage: function(id) {
|
189
|
+
return this.each(function(m) {
|
190
|
+
return m.set('selected', m.id === id);
|
191
|
+
});
|
192
|
+
}
|
193
|
+
});
|
194
|
+
var SensorInfoList;
|
195
|
+
|
196
|
+
SensorInfoList = Backbone.Collection.extend({
|
197
|
+
model: SensorInfo,
|
198
|
+
url: function() {
|
199
|
+
return ROOT + 'sensors';
|
200
|
+
}
|
201
|
+
});
|
202
|
+
var WidgetList;
|
203
|
+
|
204
|
+
WidgetList = Backbone.Collection.extend({
|
205
|
+
model: Widget,
|
206
|
+
setContext: function(pageInfos) {
|
207
|
+
this.pageInfos = pageInfos;
|
208
|
+
},
|
209
|
+
url: function() {
|
210
|
+
return ROOT + 'pages/' + this.pageInfos.selected().id + '/widgets';
|
211
|
+
},
|
212
|
+
startPolling: function() {
|
213
|
+
var _this = this;
|
214
|
+
return setInterval(function() {
|
215
|
+
if (_this.pageInfos.selected()) {
|
216
|
+
return _this.each(function(w) {
|
217
|
+
return w.refetch();
|
218
|
+
});
|
219
|
+
}
|
220
|
+
}, 200);
|
221
|
+
}
|
222
|
+
});
|
223
|
+
var WidgetPresenter;
|
224
|
+
|
225
|
+
WidgetPresenter = (function() {
|
226
|
+
|
227
|
+
function WidgetPresenter(pageInfos, model, el) {
|
228
|
+
var chartClass;
|
229
|
+
this.pageInfos = pageInfos;
|
230
|
+
this.model = model;
|
231
|
+
chartClass = this.chartClass();
|
232
|
+
this.chart = new chartClass(el);
|
233
|
+
this.draw();
|
234
|
+
}
|
235
|
+
|
236
|
+
WidgetPresenter.prototype.get = function(arg) {
|
237
|
+
return this.model.get(arg);
|
238
|
+
};
|
239
|
+
|
240
|
+
WidgetPresenter.prototype.globalOptions = function() {
|
241
|
+
return gon.options;
|
242
|
+
};
|
243
|
+
|
244
|
+
WidgetPresenter.prototype.dateOffset = function() {
|
245
|
+
if (this.globalOptions.useUtc) {
|
246
|
+
return (new Date).getTimezoneOffset() * 60000;
|
247
|
+
} else {
|
248
|
+
return 0;
|
249
|
+
}
|
250
|
+
};
|
251
|
+
|
252
|
+
WidgetPresenter.prototype.options = function() {
|
253
|
+
return {
|
254
|
+
title: this.get('title'),
|
255
|
+
height: 300,
|
256
|
+
chartArea: {
|
257
|
+
left: 10
|
258
|
+
}
|
259
|
+
};
|
260
|
+
};
|
261
|
+
|
262
|
+
WidgetPresenter.prototype.mergedOptions = function() {
|
263
|
+
var pageOptions;
|
264
|
+
pageOptions = this.pageInfos.selected() ? this.pageInfos.selected().get('gchartOptions') : {};
|
265
|
+
return $.extend(true, this.options(), this.globalOptions.gchartOptions, pageOptions, this.get('gchartOptions'));
|
266
|
+
};
|
267
|
+
|
268
|
+
WidgetPresenter.prototype.data = function() {
|
269
|
+
return new google.visualization.DataTable;
|
270
|
+
};
|
271
|
+
|
272
|
+
WidgetPresenter.prototype.chartClass = function() {
|
273
|
+
return google.visualization[this.visualization];
|
274
|
+
};
|
275
|
+
|
276
|
+
WidgetPresenter.prototype.cutoff = function() {};
|
277
|
+
|
278
|
+
WidgetPresenter.prototype.cutoffValue = function(v, min, max) {
|
279
|
+
if (v != null) {
|
280
|
+
if ((min != null) && v < min) {
|
281
|
+
return min;
|
282
|
+
} else if ((max != null) && v > max) {
|
283
|
+
return max;
|
284
|
+
} else {
|
285
|
+
return v;
|
286
|
+
}
|
287
|
+
} else {
|
288
|
+
return 0;
|
289
|
+
}
|
290
|
+
};
|
291
|
+
|
292
|
+
WidgetPresenter.prototype.draw = function(min, max) {
|
293
|
+
this.cutoff(min, max);
|
294
|
+
return this.chart.draw(this.data(), this.mergedOptions());
|
295
|
+
};
|
296
|
+
|
297
|
+
return WidgetPresenter;
|
298
|
+
|
299
|
+
})();
|
300
|
+
|
301
|
+
WidgetPresenter.create = function(pageInfos, model, el) {
|
302
|
+
var presenterClass, type;
|
303
|
+
type = model.get('type');
|
304
|
+
if ((type != null) && type.match(/^\w+$/)) {
|
305
|
+
presenterClass = eval("" + (type.capitalize()) + "Presenter");
|
306
|
+
return new presenterClass(pageInfos, model, el);
|
307
|
+
} else {
|
308
|
+
return null;
|
309
|
+
}
|
310
|
+
};
|
311
|
+
var PiePresenter,
|
312
|
+
__hasProp = {}.hasOwnProperty,
|
313
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
314
|
+
|
315
|
+
PiePresenter = (function(_super) {
|
316
|
+
|
317
|
+
__extends(PiePresenter, _super);
|
318
|
+
|
319
|
+
function PiePresenter() {
|
320
|
+
return PiePresenter.__super__.constructor.apply(this, arguments);
|
321
|
+
}
|
322
|
+
|
323
|
+
PiePresenter.prototype.visualization = 'PieChart';
|
324
|
+
|
325
|
+
PiePresenter.prototype.cutoff = function() {};
|
326
|
+
|
327
|
+
PiePresenter.prototype.data = function() {
|
328
|
+
var data;
|
329
|
+
data = PiePresenter.__super__.data.call(this);
|
330
|
+
data.addColumn('string', 'Title');
|
331
|
+
data.addColumn('number', this.get('valuesTitle'));
|
332
|
+
data.addRows(this.get('series').data);
|
333
|
+
return data;
|
334
|
+
};
|
335
|
+
|
336
|
+
PiePresenter.prototype.options = function() {
|
337
|
+
return $.extend(true, PiePresenter.__super__.options.call(this), {
|
338
|
+
slices: this.get('series').options,
|
339
|
+
legend: {
|
340
|
+
position: 'bottom'
|
341
|
+
}
|
342
|
+
});
|
343
|
+
};
|
344
|
+
|
345
|
+
return PiePresenter;
|
346
|
+
|
347
|
+
})(WidgetPresenter);
|
348
|
+
var TimelinePresenter,
|
349
|
+
__hasProp = {}.hasOwnProperty,
|
350
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
351
|
+
|
352
|
+
TimelinePresenter = (function(_super) {
|
353
|
+
|
354
|
+
__extends(TimelinePresenter, _super);
|
355
|
+
|
356
|
+
function TimelinePresenter() {
|
357
|
+
return TimelinePresenter.__super__.constructor.apply(this, arguments);
|
358
|
+
}
|
359
|
+
|
360
|
+
TimelinePresenter.prototype.data = function() {
|
361
|
+
var data, dateOffset, series;
|
362
|
+
data = TimelinePresenter.__super__.data.call(this);
|
363
|
+
data.addColumn('datetime', 'Time');
|
364
|
+
dateOffset = this.dateOffset() + this.get('interval') * 1000;
|
365
|
+
series = this.get('series');
|
366
|
+
_.each(series.titles, function(t) {
|
367
|
+
return data.addColumn('number', t);
|
368
|
+
});
|
369
|
+
_.each(series.rows, function(row) {
|
370
|
+
row[0] = new Date(row[0] + dateOffset);
|
371
|
+
return data.addRow(row);
|
372
|
+
});
|
373
|
+
return data;
|
374
|
+
};
|
375
|
+
|
376
|
+
return TimelinePresenter;
|
377
|
+
|
378
|
+
})(WidgetPresenter);
|
379
|
+
var SeriesPresenter,
|
380
|
+
__hasProp = {}.hasOwnProperty,
|
381
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
382
|
+
|
383
|
+
SeriesPresenter = (function(_super) {
|
384
|
+
|
385
|
+
__extends(SeriesPresenter, _super);
|
386
|
+
|
387
|
+
function SeriesPresenter() {
|
388
|
+
return SeriesPresenter.__super__.constructor.apply(this, arguments);
|
389
|
+
}
|
390
|
+
|
391
|
+
SeriesPresenter.prototype.options = function() {
|
392
|
+
var format, secondPart;
|
393
|
+
secondPart = this.get('interval') % 60 === 0 ? '' : ':ss';
|
394
|
+
format = this.model.timespan() > 24 * 60 * 60 ? "yyyy.MM.dd HH:mm" + secondPart : "HH:mm" + secondPart;
|
395
|
+
return $.extend(true, SeriesPresenter.__super__.options.call(this), {
|
396
|
+
lineWidth: 1,
|
397
|
+
chartArea: {
|
398
|
+
width: '100%'
|
399
|
+
},
|
400
|
+
legend: {
|
401
|
+
position: 'bottom'
|
402
|
+
},
|
403
|
+
vAxis: {
|
404
|
+
title: this.valuesTitle(),
|
405
|
+
textPosition: 'in'
|
406
|
+
},
|
407
|
+
hAxis: {
|
408
|
+
format: format
|
409
|
+
},
|
410
|
+
series: this.get('series').options,
|
411
|
+
axisTitlesPosition: 'in'
|
412
|
+
});
|
413
|
+
};
|
414
|
+
|
415
|
+
SeriesPresenter.prototype.valuesTitle = function() {
|
416
|
+
if (this.get('valuesTitle')) {
|
417
|
+
return "" + (this.get('valuesTitle')) + " / " + (this.humanizedInterval());
|
418
|
+
} else {
|
419
|
+
return this.humanizedInterval();
|
420
|
+
}
|
421
|
+
};
|
422
|
+
|
423
|
+
SeriesPresenter.prototype.humanizedInterval = function() {
|
424
|
+
return this.get('interval').humanize();
|
425
|
+
};
|
426
|
+
|
427
|
+
SeriesPresenter.prototype.cutoff = function(min, max) {
|
428
|
+
var _this = this;
|
429
|
+
return _.each(this.get('series').rows, function(row) {
|
430
|
+
var i, value, _i, _ref, _results;
|
431
|
+
_results = [];
|
432
|
+
for (i = _i = 1, _ref = row.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
|
433
|
+
value = row[i];
|
434
|
+
if (value == null) {
|
435
|
+
value = 0;
|
436
|
+
}
|
437
|
+
_results.push(row[i] = _this.cutoffValue(value, min, max));
|
438
|
+
}
|
439
|
+
return _results;
|
440
|
+
});
|
441
|
+
};
|
442
|
+
|
443
|
+
return SeriesPresenter;
|
444
|
+
|
445
|
+
})(TimelinePresenter);
|
446
|
+
var LinePresenter,
|
447
|
+
__hasProp = {}.hasOwnProperty,
|
448
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
449
|
+
|
450
|
+
LinePresenter = (function(_super) {
|
451
|
+
|
452
|
+
__extends(LinePresenter, _super);
|
453
|
+
|
454
|
+
function LinePresenter() {
|
455
|
+
return LinePresenter.__super__.constructor.apply(this, arguments);
|
456
|
+
}
|
457
|
+
|
458
|
+
LinePresenter.prototype.visualization = 'LineChart';
|
459
|
+
|
460
|
+
return LinePresenter;
|
461
|
+
|
462
|
+
})(SeriesPresenter);
|
463
|
+
var AreaPresenter,
|
464
|
+
__hasProp = {}.hasOwnProperty,
|
465
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
466
|
+
|
467
|
+
AreaPresenter = (function(_super) {
|
468
|
+
|
469
|
+
__extends(AreaPresenter, _super);
|
470
|
+
|
471
|
+
function AreaPresenter() {
|
472
|
+
return AreaPresenter.__super__.constructor.apply(this, arguments);
|
473
|
+
}
|
474
|
+
|
475
|
+
AreaPresenter.prototype.visualization = 'AreaChart';
|
476
|
+
|
477
|
+
return AreaPresenter;
|
478
|
+
|
479
|
+
})(SeriesPresenter);
|
480
|
+
var TablePresenter,
|
481
|
+
__hasProp = {}.hasOwnProperty,
|
482
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
483
|
+
|
484
|
+
TablePresenter = (function(_super) {
|
485
|
+
|
486
|
+
__extends(TablePresenter, _super);
|
487
|
+
|
488
|
+
function TablePresenter() {
|
489
|
+
return TablePresenter.__super__.constructor.apply(this, arguments);
|
490
|
+
}
|
491
|
+
|
492
|
+
TablePresenter.prototype.visualization = 'Table';
|
493
|
+
|
494
|
+
TablePresenter.prototype.cutoff = function() {};
|
495
|
+
|
496
|
+
TablePresenter.prototype.options = function() {
|
497
|
+
return $.extend(true, TablePresenter.__super__.options.call(this), {
|
498
|
+
sortColumn: 0,
|
499
|
+
sortAscending: false
|
500
|
+
});
|
501
|
+
};
|
502
|
+
|
503
|
+
return TablePresenter;
|
504
|
+
|
505
|
+
})(TimelinePresenter);
|
506
|
+
var GaugePresenter,
|
507
|
+
__hasProp = {}.hasOwnProperty,
|
508
|
+
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
509
|
+
|
510
|
+
GaugePresenter = (function(_super) {
|
511
|
+
|
512
|
+
__extends(GaugePresenter, _super);
|
513
|
+
|
514
|
+
function GaugePresenter() {
|
515
|
+
return GaugePresenter.__super__.constructor.apply(this, arguments);
|
516
|
+
}
|
517
|
+
|
518
|
+
GaugePresenter.prototype.visualization = 'Gauge';
|
519
|
+
|
520
|
+
GaugePresenter.prototype.cutoff = function() {};
|
521
|
+
|
522
|
+
GaugePresenter.prototype.data = function() {
|
523
|
+
var data;
|
524
|
+
data = GaugePresenter.__super__.data.call(this);
|
525
|
+
data.addColumn('string', 'Label');
|
526
|
+
data.addColumn('number', this.get('valuesTitle'));
|
527
|
+
data.addRows(this.get('series'));
|
528
|
+
return data;
|
529
|
+
};
|
530
|
+
|
531
|
+
return GaugePresenter;
|
532
|
+
|
533
|
+
})(WidgetPresenter);
|
534
|
+
var PageTitleView;
|
535
|
+
|
536
|
+
PageTitleView = Backbone.View.extend({
|
537
|
+
tagName: 'li',
|
538
|
+
template: _.template('<a href="#/pages/<%= id %>"><%= title %></a>'),
|
539
|
+
initialize: function() {
|
540
|
+
this.model.bind('change', this.render, this);
|
541
|
+
return this.model.bind('destroy', this.remove, this);
|
542
|
+
},
|
543
|
+
render: function() {
|
544
|
+
this.$el.html(this.template(this.model.toJSON()));
|
545
|
+
if (this.model.get('selected')) {
|
546
|
+
return this.$el.addClass('active');
|
547
|
+
} else {
|
548
|
+
return this.$el.removeClass('active');
|
549
|
+
}
|
550
|
+
}
|
551
|
+
});
|
552
|
+
var PageTitlesView;
|
553
|
+
|
554
|
+
PageTitlesView = Backbone.View.extend({
|
555
|
+
initialize: function(pageInfos) {
|
556
|
+
this.pageInfos = pageInfos;
|
557
|
+
return this.pageInfos.bind('reset', this.render, this);
|
558
|
+
},
|
559
|
+
addOne: function(pageInfo) {
|
560
|
+
var view;
|
561
|
+
view = new PageTitleView({
|
562
|
+
model: pageInfo
|
563
|
+
});
|
564
|
+
view.render();
|
565
|
+
return $('#page-titles').append(view.el);
|
566
|
+
},
|
567
|
+
render: function() {
|
568
|
+
$('#page-titles').empty();
|
569
|
+
return this.pageInfos.each(this.addOne);
|
570
|
+
}
|
571
|
+
});
|
572
|
+
var SensorInfoListView;
|
573
|
+
|
574
|
+
SensorInfoListView = Backbone.View.extend({
|
575
|
+
tagName: 'div',
|
576
|
+
template: function() {
|
577
|
+
return _.template($("#sensor-list").html());
|
578
|
+
},
|
579
|
+
initialize: function(sensorInfo) {
|
580
|
+
this.sensorInfo = sensorInfo;
|
581
|
+
return this.sensorInfo.bind('reset', this.render, this);
|
582
|
+
},
|
583
|
+
render: function() {
|
584
|
+
return this.$el.html(this.template()({
|
585
|
+
sensors: this.sensorInfo.toJSON()
|
586
|
+
}));
|
587
|
+
},
|
588
|
+
selectedSensors: function() {
|
589
|
+
var checked, ids, selected;
|
590
|
+
checked = _.filter(this.$el.find('.sensor-box'), function(el) {
|
591
|
+
return $(el).is(':checked');
|
592
|
+
});
|
593
|
+
ids = {};
|
594
|
+
_.each(checked, function(box) {
|
595
|
+
return ids[box.id] = true;
|
596
|
+
});
|
597
|
+
return selected = this.sensorInfo.filter(function(sensor) {
|
598
|
+
return ids[sensor.id];
|
599
|
+
});
|
600
|
+
}
|
601
|
+
});
|
602
|
+
var DynamicChartView;
|
603
|
+
|
604
|
+
DynamicChartView = Backbone.View.extend({
|
605
|
+
initialize: function(options) {
|
606
|
+
this.pageInfos = options['pageInfos'];
|
607
|
+
this.sensors = [];
|
608
|
+
this.type = 'Area';
|
609
|
+
this.widget = new DynamicWidget;
|
610
|
+
this.widget.bind('destroy', this.remove, this);
|
611
|
+
return this.widget.bind('redraw', this.redrawChart, this);
|
612
|
+
},
|
613
|
+
tagName: 'div',
|
614
|
+
events: {
|
615
|
+
"click #refresh-chart": 'update',
|
616
|
+
"click #extend-timespan": 'extendTimespan',
|
617
|
+
"click #reset-timespan": 'resetTimespan',
|
618
|
+
"change #start-time input": 'maybeEnableStopTime',
|
619
|
+
"click #set-interval": 'setTimelineInterval'
|
620
|
+
},
|
621
|
+
template: function() {
|
622
|
+
return _.template($("#dynamic-widget-plotarea").html());
|
623
|
+
},
|
624
|
+
render: function() {
|
625
|
+
this.$el.html(this.template()());
|
626
|
+
return this.initDatePickers();
|
627
|
+
},
|
628
|
+
initDatePickers: function() {
|
629
|
+
this.$el.find(".datepicker").each(function(i) {
|
630
|
+
return $(this).datetimepicker({
|
631
|
+
showOtherMonths: true,
|
632
|
+
selectOtherMonths: true
|
633
|
+
});
|
634
|
+
});
|
635
|
+
return this.$el.find("#end-time input").prop("disabled", true);
|
636
|
+
},
|
637
|
+
setTimelineInterval: function() {
|
638
|
+
var end, start;
|
639
|
+
start = this.unixtimeFromDatepicker("#start-time input");
|
640
|
+
end = this.unixtimeFromDatepicker("#end-time input");
|
641
|
+
this.widget.setStartTime(start);
|
642
|
+
this.widget.setEndTime(end);
|
643
|
+
return this.update();
|
644
|
+
},
|
645
|
+
dateFromDatepicker: function(id) {
|
646
|
+
return this.$el.find(id).datetimepicker("getDate");
|
647
|
+
},
|
648
|
+
unixtimeFromDatepicker: function(id) {
|
649
|
+
var date;
|
650
|
+
date = this.dateFromDatepicker(id);
|
651
|
+
if (date) {
|
652
|
+
return date.getTime() / 1000;
|
653
|
+
} else {
|
654
|
+
return null;
|
655
|
+
}
|
656
|
+
},
|
657
|
+
maybeEnableStopTime: function() {
|
658
|
+
var date, disabled;
|
659
|
+
date = this.dateFromDatepicker("#start-time input");
|
660
|
+
disabled = date ? false : true;
|
661
|
+
return this.$el.find("#end-time input").prop("disabled", disabled);
|
662
|
+
},
|
663
|
+
extendTimespan: function() {
|
664
|
+
var select, val;
|
665
|
+
select = this.$el.find("#extend-timespan-val");
|
666
|
+
val = select.first().val();
|
667
|
+
this.widget.increaseTimespan(parseInt(val));
|
668
|
+
return this.update();
|
669
|
+
},
|
670
|
+
resetTimespan: function() {
|
671
|
+
this.widget.resetTimespan();
|
672
|
+
return this.update();
|
673
|
+
},
|
674
|
+
sensorIds: function() {
|
675
|
+
return _.map(this.sensors, function(s) {
|
676
|
+
return s.id;
|
677
|
+
});
|
678
|
+
},
|
679
|
+
redrawChart: function() {
|
680
|
+
if (this.presenter) {
|
681
|
+
return this.presenter.draw();
|
682
|
+
} else {
|
683
|
+
return this.presenter = WidgetPresenter.create(this.pageInfos, this.widget, this.chartContainer());
|
684
|
+
}
|
685
|
+
},
|
686
|
+
chartContainer: function() {
|
687
|
+
return this.$el.find('#chart')[0];
|
688
|
+
},
|
689
|
+
update: function() {
|
690
|
+
if (this.sensors.length > 0) {
|
691
|
+
return this.widget.forceUpdate();
|
692
|
+
}
|
693
|
+
},
|
694
|
+
draw: function(sensors, type) {
|
695
|
+
this.sensors = sensors;
|
696
|
+
this.type = type;
|
697
|
+
this.widget.set('sensorIds', this.sensorIds());
|
698
|
+
this.widget.set('type', this.type);
|
699
|
+
this.presenter = null;
|
700
|
+
$(this.chartContainer()).empty();
|
701
|
+
return this.widget.forceUpdate();
|
702
|
+
}
|
703
|
+
});
|
704
|
+
var DynamicWidgetView;
|
705
|
+
|
706
|
+
DynamicWidgetView = Backbone.View.extend({
|
707
|
+
tagName: 'div',
|
708
|
+
initialize: function(options) {
|
709
|
+
this.pageInfos = options['pageInfos'];
|
710
|
+
this.sensorInfo = new SensorInfoList;
|
711
|
+
this.sensorListView = new SensorInfoListView(this.sensorInfo);
|
712
|
+
this.chartView = new DynamicChartView({
|
713
|
+
pageInfos: this.pageInfos
|
714
|
+
});
|
715
|
+
this.$el.html(this.template()());
|
716
|
+
this.$el.find('#sensor-list-area').append(this.sensorListView.el);
|
717
|
+
this.chartView.render();
|
718
|
+
return this.$el.find('#dynamic-plotarea').append(this.chartView.el);
|
719
|
+
},
|
720
|
+
events: {
|
721
|
+
"click #sensor-controls #refresh": 'refresh',
|
722
|
+
"click #sensor-controls #draw": 'drawChart'
|
723
|
+
},
|
724
|
+
template: function() {
|
725
|
+
return _.template($("#dynamic-widget").html());
|
726
|
+
},
|
727
|
+
errorTemplate: function() {
|
728
|
+
return _.template($("#dynamic-widget-error").html());
|
729
|
+
},
|
730
|
+
error: function(error) {
|
731
|
+
return this.$el.find('#errors').append(this.errorTemplate()({
|
732
|
+
error: error
|
733
|
+
}));
|
734
|
+
},
|
735
|
+
refresh: function() {
|
736
|
+
return this.sensorInfo.fetch();
|
737
|
+
},
|
738
|
+
intervalsEqual: function(sensors) {
|
739
|
+
var badIntervals, interval;
|
740
|
+
interval = sensors[0].get('interval');
|
741
|
+
badIntervals = _.filter(sensors, function(s) {
|
742
|
+
return s.get('interval') !== interval;
|
743
|
+
});
|
744
|
+
return badIntervals.length === 0;
|
745
|
+
},
|
746
|
+
drawChart: function() {
|
747
|
+
var selectedSensors, type;
|
748
|
+
selectedSensors = this.sensorListView.selectedSensors();
|
749
|
+
if (!(selectedSensors.length > 0)) {
|
750
|
+
return;
|
751
|
+
}
|
752
|
+
if (!this.intervalsEqual(selectedSensors)) {
|
753
|
+
this.error('Selected sensors have different intervals');
|
754
|
+
return;
|
755
|
+
}
|
756
|
+
type = this.$el.find('#chart-type').val();
|
757
|
+
return this.chartView.draw(selectedSensors, type);
|
758
|
+
},
|
759
|
+
render: function(container) {
|
760
|
+
container.empty();
|
761
|
+
container.append(this.$el);
|
762
|
+
this.sensorInfo.fetch();
|
763
|
+
return this.chartView.update();
|
764
|
+
}
|
765
|
+
});
|
766
|
+
var WidgetChartView;
|
767
|
+
|
768
|
+
WidgetChartView = Backbone.View.extend({
|
769
|
+
tagName: 'div',
|
770
|
+
initialize: function(options) {
|
771
|
+
this.pageInfos = options['pageInfos'];
|
772
|
+
return this.model.bind('destroy', this.remove, this);
|
773
|
+
},
|
774
|
+
updateData: function(min, max) {
|
775
|
+
return this.presenter.draw(min, max);
|
776
|
+
},
|
777
|
+
render: function() {
|
778
|
+
return this.presenter = WidgetPresenter.create(this.pageInfos, this.model, this.el);
|
779
|
+
}
|
780
|
+
});
|
781
|
+
var WidgetView;
|
782
|
+
|
783
|
+
WidgetView = Backbone.View.extend({
|
784
|
+
tagName: 'div',
|
785
|
+
template: function(args) {
|
786
|
+
return _.template($(".widget-template[data-widget-type=\"" + (this.model.get('type')) + "\"]").html())(args);
|
787
|
+
},
|
788
|
+
initialize: function(options) {
|
789
|
+
this.pageInfos = options['pageInfos'];
|
790
|
+
this.model.bind('destroy', this.remove, this);
|
791
|
+
return this.model.bind('redraw', this.updateChart, this);
|
792
|
+
},
|
793
|
+
events: {
|
794
|
+
"click #refresh": 'refresh',
|
795
|
+
"click #need-refresh": 'setRefresh',
|
796
|
+
"click #extend-timespan": 'extendTimespan',
|
797
|
+
"click #reset-timespan": 'resetTimespan',
|
798
|
+
"change #start-time input": 'maybeEnableStopTime',
|
799
|
+
"click #set-interval": 'setTimelineInterval'
|
800
|
+
},
|
801
|
+
refresh: function() {
|
802
|
+
return this.model.forceUpdate();
|
803
|
+
},
|
804
|
+
setRefresh: function() {
|
805
|
+
var needRefresh;
|
806
|
+
needRefresh = this.$el.find('#need-refresh').is(":checked");
|
807
|
+
this.model.setRefresh(needRefresh);
|
808
|
+
return true;
|
809
|
+
},
|
810
|
+
extendTimespan: function() {
|
811
|
+
var select, val;
|
812
|
+
select = this.$el.find("#extend-timespan-val");
|
813
|
+
val = select.first().val();
|
814
|
+
return this.model.increaseTimespan(parseInt(val));
|
815
|
+
},
|
816
|
+
setTimelineInterval: function() {
|
817
|
+
var end, start;
|
818
|
+
start = this.unixtimeFromDatepicker("#start-time input");
|
819
|
+
end = this.unixtimeFromDatepicker("#end-time input");
|
820
|
+
this.model.setStartTime(start);
|
821
|
+
return this.model.setEndTime(end);
|
822
|
+
},
|
823
|
+
maybeEnableStopTime: function() {
|
824
|
+
var date, disabled;
|
825
|
+
date = this.dateFromDatepicker("#start-time input");
|
826
|
+
disabled = date ? false : true;
|
827
|
+
return this.$el.find("#end-time input").prop("disabled", disabled);
|
828
|
+
},
|
829
|
+
resetTimespan: function() {
|
830
|
+
return this.model.resetTimespan();
|
831
|
+
},
|
832
|
+
renderChart: function() {
|
833
|
+
return this.chartView.render();
|
834
|
+
},
|
835
|
+
updateChart: function() {
|
836
|
+
return this.chartView.updateData(this.cutoffMin(), this.cutoffMax());
|
837
|
+
},
|
838
|
+
setIds: function() {
|
839
|
+
this.$el.find('#configure-button').prop('href', "#configure-" + this.model.id);
|
840
|
+
this.$el.find('#configure').attr('id', "configure-" + this.model.id);
|
841
|
+
this.$el.find('#start-time input').attr('id', "start-time-" + this.model.id);
|
842
|
+
return this.$el.find('#end-time input').attr('id', "end-time-" + this.model.id);
|
843
|
+
},
|
844
|
+
render: function() {
|
845
|
+
this.$el.html(this.template(this.model.toJSON()));
|
846
|
+
this.setIds();
|
847
|
+
this.chartView = new WidgetChartView({
|
848
|
+
pageInfos: this.pageInfos,
|
849
|
+
model: this.model
|
850
|
+
});
|
851
|
+
this.$el.find("#plotarea").append(this.chartView.el);
|
852
|
+
this.$el.addClass("span" + (this.model.get('width')));
|
853
|
+
return this.initDatePickers();
|
854
|
+
},
|
855
|
+
initDatePickers: function() {
|
856
|
+
this.$el.find(".datepicker").each(function(i) {
|
857
|
+
return $(this).datetimepicker({
|
858
|
+
showOtherMonths: true,
|
859
|
+
selectOtherMonths: true
|
860
|
+
});
|
861
|
+
});
|
862
|
+
return this.$el.find("#end-time input").prop("disabled", true);
|
863
|
+
},
|
864
|
+
cutoffMin: function() {
|
865
|
+
var val;
|
866
|
+
val = parseFloat(this.controlValue('#cutoff-min'));
|
867
|
+
if (_.isNaN(val)) {
|
868
|
+
return null;
|
869
|
+
} else {
|
870
|
+
return val;
|
871
|
+
}
|
872
|
+
},
|
873
|
+
cutoffMax: function() {
|
874
|
+
var val;
|
875
|
+
val = parseFloat(this.controlValue('#cutoff-max'));
|
876
|
+
if (_.isNaN(val)) {
|
877
|
+
return null;
|
878
|
+
} else {
|
879
|
+
return val;
|
880
|
+
}
|
881
|
+
},
|
882
|
+
controlValue: function(id) {
|
883
|
+
var val;
|
884
|
+
return val = this.$el.find(id).first().val();
|
885
|
+
},
|
886
|
+
dateFromDatepicker: function(id) {
|
887
|
+
return this.$el.find(id).datetimepicker("getDate");
|
888
|
+
},
|
889
|
+
unixtimeFromDatepicker: function(id) {
|
890
|
+
var date;
|
891
|
+
date = this.dateFromDatepicker(id);
|
892
|
+
if (date) {
|
893
|
+
return date.getTime() / 1000;
|
894
|
+
} else {
|
895
|
+
return null;
|
896
|
+
}
|
897
|
+
}
|
898
|
+
});
|
899
|
+
var WidgetListView;
|
900
|
+
|
901
|
+
WidgetListView = Backbone.View.extend({
|
902
|
+
initialize: function(options) {
|
903
|
+
this.widgetList = options['widgetList'];
|
904
|
+
this.pageInfos = options['pageInfos'];
|
905
|
+
return this.widgetList.bind('reset', this.render, this);
|
906
|
+
},
|
907
|
+
render: function() {
|
908
|
+
var container,
|
909
|
+
_this = this;
|
910
|
+
container = $('#widgets');
|
911
|
+
container.empty();
|
912
|
+
return this.widgetList.each(function(w) {
|
913
|
+
var view;
|
914
|
+
view = new WidgetView({
|
915
|
+
pageInfos: _this.pageInfos,
|
916
|
+
model: w
|
917
|
+
});
|
918
|
+
view.render();
|
919
|
+
container.append(view.el);
|
920
|
+
return view.renderChart();
|
921
|
+
});
|
922
|
+
}
|
923
|
+
});
|
924
|
+
var AppRouter;
|
925
|
+
|
926
|
+
AppRouter = Backbone.Router.extend({
|
927
|
+
initialize: function(pageInfos, widgetList) {
|
928
|
+
this.pageInfos = pageInfos;
|
929
|
+
this.widgetList = widgetList;
|
930
|
+
},
|
931
|
+
routes: {
|
932
|
+
'pages/:id': 'getPage',
|
933
|
+
'custom': 'custom',
|
934
|
+
'*actions': 'defaultRoute'
|
935
|
+
},
|
936
|
+
getPage: function(ids) {
|
937
|
+
var id;
|
938
|
+
id = parseInt(ids);
|
939
|
+
this.pageInfos.selectPage(id);
|
940
|
+
return this.widgetList.fetch();
|
941
|
+
},
|
942
|
+
custom: function() {
|
943
|
+
var dynamicWidget;
|
944
|
+
this.pageInfos.selectNone();
|
945
|
+
dynamicWidget = new DynamicWidgetView({
|
946
|
+
pageInfos: this.pageInfos
|
947
|
+
});
|
948
|
+
return dynamicWidget.render($('#widgets'));
|
949
|
+
},
|
950
|
+
defaultRoute: function(actions) {
|
951
|
+
if (this.pageInfos.length > 0) {
|
952
|
+
return this.navigate('//pages/1');
|
953
|
+
} else {
|
954
|
+
return this.navigate('//custom');
|
955
|
+
}
|
956
|
+
}
|
957
|
+
});
|
958
|
+
|
959
|
+
document.startApp = function() {
|
960
|
+
var appRouter, pageInfos, pageTitlesApp, widgetList, widgetListApp;
|
961
|
+
pageInfos = new PageInfoList;
|
962
|
+
pageTitlesApp = new PageTitlesView(pageInfos);
|
963
|
+
pageInfos.reset(gon.pageInfos);
|
964
|
+
widgetList = new WidgetList;
|
965
|
+
widgetList.setContext(pageInfos);
|
966
|
+
widgetList.startPolling();
|
967
|
+
widgetListApp = new WidgetListView({
|
968
|
+
widgetList: widgetList,
|
969
|
+
pageInfos: pageInfos
|
970
|
+
});
|
971
|
+
appRouter = new AppRouter(pageInfos, widgetList);
|
972
|
+
return Backbone.history.start();
|
973
|
+
};
|