├── .gitignore ├── LICENSE ├── README.md ├── dynamic-highcharts-plugin-1.png ├── dynamic-highcharts-plugin-2.png ├── plugin_highcharts.js └── plugins_highcharts.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.pyc 3 | venv/ 4 | calendar.py 5 | config.ini 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # freeboard-dynamic-highcharts-plugin 2 |
Copy the file (plugin_highcharts.js from https://github.com/onlinux/freeboard-dynamic-highcharts-plugin) to your freeboard installation, for example:
16 | 17 |$ cp ./plugin_highcharts.js /freeboard/plugins/thirdparty
18 |
19 | edit the freeboard index.html file and add a link to the plugin near the end of the head.js script loader, like:
20 | 21 |head.js(
22 | 'js/freeboard_plugins.min.js',
23 | 'plugins/actuator.js',
24 | $(function() {
25 | //DOM Ready
26 | freeboard.initialize(true);
27 | })head.js(
28 | 'js/freeboard_plugins.min.js',
29 | 'plugins/thirdparty/plugin_highcharts.js',
30 | $(function() {
31 | //DOM Ready
32 | freeboard.initialize(true);
33 | })
34 |
--------------------------------------------------------------------------------
/dynamic-highcharts-plugin-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlinux/freeboard-dynamic-highcharts-plugin/14e5c014702353fe43f1418cdee1459fb307d48f/dynamic-highcharts-plugin-1.png
--------------------------------------------------------------------------------
/dynamic-highcharts-plugin-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/onlinux/freeboard-dynamic-highcharts-plugin/14e5c014702353fe43f1418cdee1459fb307d48f/dynamic-highcharts-plugin-2.png
--------------------------------------------------------------------------------
/plugin_highcharts.js:
--------------------------------------------------------------------------------
1 | // ┌────────────────────────────────────────────────────────────────────┐ \\
2 | // │ freeboard-dynamic-highcharts-plugin │ \\
3 | // ├────────────────────────────────────────────────────────────────────┤ \\
4 | // │ https://blog.onlinux.fr/?tag=freeboard │ \\
5 | // ├────────────────────────────────────────────────────────────────────┤ \\
6 | // │ Licensed under the MIT license. │ \\
7 | // ├────────────────────────────────────────────────────────────────────┤ \\
8 | // │ Freeboard widget plugin for Highcharts. │ \\
9 | // └────────────────────────────────────────────────────────────────────┘ \\
10 | (function() {
11 |
12 | //
13 | // DECLARATIONS
14 | //
15 | var HIGHCHARTS_ID = 0;
16 | var ONE_SECOND_IN_MILIS = 1000;
17 | var MAX_NUM_SERIES = 3;
18 |
19 | //
20 | // HELPERS
21 | //
22 |
23 | // Get coordinates of point
24 | function xy(obj, x, y) {
25 | return [obj[x], obj[y]]
26 | }
27 |
28 | function isNumber(n) {
29 | return !isNaN(parseFloat(n)) && isFinite(n);
30 | }
31 | //
32 | // TIME SERIES CHARTS
33 | //
34 | var highchartsLineWidgetSettings = [{
35 | "name": "timeframe",
36 | "display_name": "Timeframe (s)",
37 | "type": "text",
38 | "description": "Specify the last number of seconds you want to see.",
39 | "default_value": 60
40 | }, {
41 | "name": "blocks",
42 | "display_name": "Height (No. Blocks)",
43 | "type": "text",
44 | "default_value": 4
45 | }, {
46 | "name": "chartType",
47 | "display_name": "Chart Type",
48 | "type": "option",
49 | "options": [{
50 | "name": "Area",
51 | "value": "area"
52 | }, {
53 | "name": "Spline",
54 | "value": "spline"
55 | }]
56 | }, {
57 | "name": "title",
58 | "display_name": "Title",
59 | "type": "text"
60 | }, {
61 | "name": "xaxis",
62 | "display_name": "X-Axis",
63 | "type": "calculated",
64 | "default_value": "{\"title\":{\"text\" : \"Time\"}, \"type\": \"datetime\", \"floor\":0}"
65 | }, {
66 | "name": "yaxis",
67 | "display_name": "Y-Axis",
68 | "type": "calculated",
69 | "default_value": "{\"title\":{\"text\" : \"Values\"}, \"minorTickInterval\":\"auto\", \"floor\":0}"
70 | }];
71 |
72 | for (i = 1; i <= MAX_NUM_SERIES; i++) {
73 | var dataSource = {
74 | "name": "series" + i,
75 | "display_name": "Series " + i + " - Datasource",
76 | "type": "calculated"
77 | };
78 |
79 | var xField = {
80 | "name": "series" + i + "label",
81 | "display_name": "Series " + i + " - Label",
82 | "type": "text",
83 | };
84 |
85 | highchartsLineWidgetSettings.push(dataSource);
86 | highchartsLineWidgetSettings.push(xField);
87 | }
88 |
89 | freeboard
90 | .loadWidgetPlugin({
91 | "type_name": "highcharts-timeseries",
92 | "display_name": "Time series (Highcharts)",
93 | "description": "Time series line chart.",
94 | "external_scripts": [
95 | "https://code.highcharts.com/8.0.0/highcharts.js",
96 | "https://code.highcharts.com/8.0.0/modules/exporting.js"
97 | ],
98 | "fill_size": true,
99 | "settings": highchartsLineWidgetSettings,
100 | newInstance: function(settings, newInstanceCallback) {
101 | newInstanceCallback(new highchartsTimeseriesWidgetPlugin(
102 | settings));
103 | }
104 | });
105 |
106 | var highchartsTimeseriesWidgetPlugin = function(settings) {
107 |
108 | var self = this;
109 | var currentSettings = settings;
110 |
111 | var thisWidgetId = "highcharts-widget-timeseries-" + HIGHCHARTS_ID++;
112 | var thisWidgetContainer = $('');
113 |
114 | function createWidget() {
115 |
116 | Highcharts.theme = {
117 | global: {
118 | useUTC: false
119 | },
120 | colors: ["#2b908f", "#90ee7e", "#f45b5b", "#7798BF", "#aaeeee",
121 | "#ff0066", "#eeaaee", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"
122 | ],
123 | chart: {
124 | backgroundColor: null,
125 | style: {
126 | fontFamily: "'Open Sans', sans-serif"
127 | },
128 | plotBorderColor: '#606063'
129 | },
130 | title: {
131 | style: {
132 | color: '#E0E0E3',
133 | fontSize: '20px'
134 | }
135 | },
136 | subtitle: {
137 | style: {
138 | color: '#E0E0E3',
139 | textTransform: 'uppercase'
140 | }
141 | },
142 | xAxis: {
143 | gridLineColor: '#707073',
144 | labels: {
145 | style: {
146 | color: '#E0E0E3'
147 | }
148 | },
149 | lineColor: '#707073',
150 | minorGridLineColor: '#505053',
151 | tickColor: '#707073',
152 | title: {
153 | style: {
154 | color: '#A0A0A3'
155 |
156 | }
157 | }
158 | },
159 | yAxis: {
160 | gridLineColor: '#707073',
161 | labels: {
162 | style: {
163 | color: '#E0E0E3'
164 | }
165 | },
166 | lineColor: '#707073',
167 | minorGridLineColor: '#505053',
168 | tickColor: '#707073',
169 | tickWidth: 1,
170 | title: {
171 | style: {
172 | color: '#A0A0A3'
173 | }
174 | }
175 | },
176 | tooltip: {
177 | backgroundColor: 'rgba(0, 0, 0, 0.85)',
178 | style: {
179 | color: '#F0F0F0'
180 | }
181 | },
182 | plotOptions: {
183 | series: {
184 | dataLabels: {
185 | color: '#B0B0B3'
186 | },
187 | marker: {
188 | lineColor: '#333'
189 | }
190 | },
191 | boxplot: {
192 | fillColor: '#505053'
193 | },
194 | candlestick: {
195 | lineColor: 'white'
196 | },
197 | errorbar: {
198 | color: 'white'
199 | }
200 | },
201 | legend: {
202 | itemStyle: {
203 | color: '#E0E0E3'
204 | },
205 | itemHoverStyle: {
206 | color: '#FFF'
207 | },
208 | itemHiddenStyle: {
209 | color: '#606063'
210 | }
211 | },
212 | credits: {
213 | style: {
214 | color: '#666'
215 | }
216 | },
217 | labels: {
218 | style: {
219 | color: '#707073'
220 | }
221 | },
222 |
223 | drilldown: {
224 | activeAxisLabelStyle: {
225 | color: '#F0F0F3'
226 | },
227 | activeDataLabelStyle: {
228 | color: '#F0F0F3'
229 | }
230 | },
231 |
232 | navigation: {
233 | buttonOptions: {
234 | symbolStroke: '#DDDDDD',
235 | theme: {
236 | fill: '#505053'
237 | }
238 | }
239 | },
240 |
241 | // scroll charts
242 | rangeSelector: {
243 | buttonTheme: {
244 | fill: '#505053',
245 | stroke: '#000000',
246 | style: {
247 | color: '#CCC'
248 | },
249 | states: {
250 | hover: {
251 | fill: '#707073',
252 | stroke: '#000000',
253 | style: {
254 | color: 'white'
255 | }
256 | },
257 | select: {
258 | fill: '#000003',
259 | stroke: '#000000',
260 | style: {
261 | color: 'white'
262 | }
263 | }
264 | }
265 | },
266 | inputBoxBorderColor: '#505053',
267 | inputStyle: {
268 | backgroundColor: '#333',
269 | color: 'silver'
270 | },
271 | labelStyle: {
272 | color: 'silver'
273 | }
274 | },
275 |
276 | navigator: {
277 | handles: {
278 | backgroundColor: '#666',
279 | borderColor: '#AAA'
280 | },
281 | outlineColor: '#CCC',
282 | maskFill: 'rgba(255,255,255,0.1)',
283 | series: {
284 | color: '#7798BF',
285 | lineColor: '#A6C7ED'
286 | },
287 | xAxis: {
288 | gridLineColor: '#505053'
289 | }
290 | },
291 |
292 | scrollbar: {
293 | barBackgroundColor: '#808083',
294 | barBorderColor: '#808083',
295 | buttonArrowColor: '#CCC',
296 | buttonBackgroundColor: '#606063',
297 | buttonBorderColor: '#606063',
298 | rifleColor: '#FFF',
299 | trackBackgroundColor: '#404043',
300 | trackBorderColor: '#404043'
301 | },
302 |
303 | // special colors for some of the
304 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)',
305 | background2: '#505053',
306 | dataLabelsColor: '#B0B0B3',
307 | textColor: '#C0C0C0',
308 | contrastTextColor: '#F0F0F3',
309 | maskColor: 'rgba(255,255,255,0.3)'
310 | };
311 |
312 | Highcharts.setOptions(Highcharts.theme);
313 |
314 | // Get widget configurations
315 | var thisWidgetXAxis = JSON.parse(currentSettings.xaxis);
316 | var thisWidgetYAxis = JSON.parse(currentSettings.yaxis);
317 | var thisWidgetTitle = currentSettings.title;
318 | var thisWidgetChartType = currentSettings.chartType;
319 | //console.log('chartType:' + currentSettings.chartType + ' ' + thisWidgetChartType);
320 | var thisWidgetSeries = [];
321 |
322 | for (i = 1; i <= MAX_NUM_SERIES; i++) {
323 | var datasource = currentSettings['series' + i];
324 | if (datasource) {
325 | var serieno = "series" + i + "label";
326 | var label = currentSettings[serieno];
327 | console.log('label: ', label);
328 | var newSeries = {
329 | id: 'series' + i,
330 | name: label,
331 | fillColor: {
332 | linearGradient: {
333 | x1: 0,
334 | y1: 0,
335 | x2: 0,
336 | y2: 1
337 | },
338 | stops: [
339 | [0, Highcharts.getOptions().colors[i - 1]],
340 | //[1, 'rgba(2,0,0,0)']
341 | [1, Highcharts.Color(Highcharts.getOptions().colors[i - 1]).setOpacity(0).get('rgba')]
342 | ]
343 | },
344 |
345 | data: [],
346 | connectNulls: true
347 | };
348 |
349 | thisWidgetSeries.push(newSeries);
350 | }
351 | }
352 |
353 | // Create widget
354 | thisWidgetContainer
355 | .css('height', 60 * self.getHeight() - 10 + 'px');
356 | thisWidgetContainer.css('width', '100%');
357 |
358 | thisWidgetContainer.highcharts({
359 | chart: {
360 | type: thisWidgetChartType,
361 | animation: Highcharts.svg,
362 | marginRight: 20
363 | },
364 | title: {
365 | text: thisWidgetTitle
366 | },
367 | xAxis: thisWidgetXAxis,
368 | yAxis: thisWidgetYAxis,
369 |
370 | plotOptions: {
371 | area: {
372 | marker: {
373 | enabled: false,
374 | symbol: 'circle',
375 | radius: 2,
376 | hover: {
377 | enabled: true
378 | }
379 | },
380 | lineWidth: 2,
381 | states: {
382 | hover: {
383 | lineWidth: 2
384 | }
385 | },
386 | threshold: null
387 | }
388 | },
389 |
390 | tooltip: {
391 | formatter: function() {
392 | return '' + this.series.name + '