diff --git a/PythonServer/screens/ts2.py b/PythonServer/screens/ts2.py index 49488fc6ec9776d62809678bef91342c0316d101..526bae68928f59eaebfa40717104da0dfbd2951f 100755 --- a/PythonServer/screens/ts2.py +++ b/PythonServer/screens/ts2.py @@ -9,7 +9,7 @@ class ts2Screen(Thread): self.stop_signal = stop_signal def run(self): - pvs = ['CrS-TICP:Cryo-TE-31491:Val', 'TS2-010CDL:Cryo-TE-82313:MeasValue', 'TS2-010CDL:Cryo-TE-82360:MeasValue', 'TS2-010CRM:Cryo-TE-068:MeasValue', 'TS2-010CRM:Cryo-TE-063:MeasValue', 'TS2-010CRM:Cryo-TE-069:MeasValue', 'TS2-010CRM:Cryo-TE-064:MeasValue', 'TS2-010CDL:Cryo-TE-82365:MeasValue', 'TS2-010CDL:Cryo-TE-82314:MeasValue', 'CrS-TICP:Cryo-TE-31492:Val'] + pvs = ['CrS-TICP:Cryo-TE-31491:Val', 'TS2-010CDL:Cryo-TE-82313:MeasValue', 'TS2-010CDL:Cryo-TE-82360:MeasValue', 'TS2-010CRM:Cryo-TE-068:MeasValue', 'TS2-010CRM:Cryo-TE-063:MeasValue', 'TS2-010CRM:Cryo-TE-069:MeasValue', 'TS2-010CRM:Cryo-TE-064:MeasValue', 'TS2-010CDL:Cryo-TE-82365:MeasValue', 'TS2-010CDL:Cryo-TE-82314:MeasValue', 'CrS-TICP:Cryo-TE-31492:Val', 'TS2-010CRM:Cryo-TE-010:MeasValue', 'TS2-010CRM:Cryo-TE-018:MeasValue', 'TS2-010CRM:Cryo-TE-019:MeasValue', 'TS2-010CRM:Cryo-TE-020:MeasValue', 'TS2-010CRM:Cryo-TE-021:MeasValue', 'TS2-010CRM:Cryo-TE-022:MeasValue', 'TS2-010CRM:Cryo-TE-028:MeasValue', 'TS2-010CRM:Cryo-TE-029:MeasValue', 'TS2-010CRM:Cryo-TE-030:MeasValue', 'TS2-010CRM:Cryo-TE-031:MeasValue', 'TS2-010CRM:Cryo-TE-032:MeasValue', 'TS2-010CRM:Cryo-TE-038:MeasValue', 'TS2-010CRM:Cryo-TE-039:MeasValue', 'TS2-010CRM:Cryo-TE-041:MeasValue', 'TS2-010CRM:Cryo-TE-042:MeasValue', 'TS2-010CRM:Cryo-TE-048:MeasValue', 'TS2-010CRM:Cryo-TE-049:MeasValue'] epics_dict={} for pv in pvs: diff --git a/WebSites/ts2/dashboard.json b/WebSites/ts2/dashboard.json index 1e83b6998fa5d8790f8bb7e47850061d03e90a14..5ad3955b47b990062012480fce6118afaed14fac 100644 --- a/WebSites/ts2/dashboard.json +++ b/WebSites/ts2/dashboard.json @@ -30,221 +30,302 @@ ] }, { - "title": "CrS-TICP:Cryo-TE-31491:Val", + "title": "Cavity 1", "width": 1, "row": { - "4": 7 + "1": 7, + "4": 7, + "6": 7, + "7": 7 }, "col": { - "4": 1 + "1": 1, + "4": 1, + "6": 1, + "7": 1 }, "col_width": 1, "widgets": [ { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"CrS-TICP:Cryo-TE-31491:Val\"][\"value\"]", + "title": "Cernox in cold tuning system", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-018:MeasValue\"][\"value\"]", "units": "K", "min_value": "0", "max_value": "300" } - } - ] - }, - { - "title": "TS2-010CDL:Cryo-TE-82313:MeasValue", - "width": 1, - "row": { - "4": 7 - }, - "col": { - "4": 2 - }, - "col_width": 1, - "widgets": [ + }, { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82313:MeasValue\"][\"value\"]", + "title": "Cernox in helium tank boTEom", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-019:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, + "max_value": 300 + } + }, + { + "type": "gauge", + "settings": { + "title": "Cernox in helium manifold to he tank", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-010:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, "max_value": "300" } } ] }, { - "title": "TS2-010CDL:Cryo-TE-82360:MeasValue", + "title": "Cavity 2", "width": 1, "row": { - "4": 7 + "1": 27, + "4": 7, + "7": 7 }, "col": { - "4": 3 + "1": 1, + "4": 2, + "7": 2 }, "col_width": 1, "widgets": [ { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82360:MeasValue\"][\"value\"]", + "title": "Cernox in cold tuning system - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-028:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, "max_value": "300" } - } - ] - }, - { - "title": "TS2-010CRM:Cryo-TE-068:MeasValue", - "width": 1, - "row": { - "4": 7 - }, - "col": { - "4": 4 - }, - "col_width": 1, - "widgets": [ + }, { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-068:MeasValue\"][\"value\"]", + "title": "Cernox in helium tank boTEom", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-029:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, "max_value": "300" } - } - ] - }, - { - "title": "TS2-010CRM:Cryo-TE-063:MeasValue", - "width": 1, - "row": { - "4": 15 - }, - "col": { - "4": 1 - }, - "col_width": 1, - "widgets": [ + }, { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-063:MeasValue\"][\"value\"]", + "title": "Cernox in helium manifold to he tank", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-020:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, "max_value": "300" } - } - ] - }, - { - "title": "TS2-010CRM:Cryo-TE-069:MeasValue", - "width": 1, - "row": { - "4": 15 - }, - "col": { - "4": 2 - }, - "col_width": 1, - "widgets": [ + }, { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-069:MeasValue\"][\"value\"]", + "title": "PT100 in Power Coupler - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-021:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, "max_value": "300" } - } - ] - }, - { - "title": "TS2-010CRM:Cryo-TE-064:MeasValue", - "width": 1, - "row": { - "4": 15 - }, - "col": { - "4": 3 - }, - "col_width": 1, - "widgets": [ + }, { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-064:MeasValue\"][\"value\"]", + "title": "Power Coupler double wall cooling - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-022:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, "max_value": "300" } } ] }, { - "title": "TS2-010CDL:Cryo-TE-82365:MeasValue", + "title": "Cavity 3", "width": 1, "row": { - "4": 15 + "1": 59, + "4": 7, + "7": 7 }, "col": { - "4": 4 + "1": 1, + "4": 3, + "7": 3 }, "col_width": 1, "widgets": [ { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82365:MeasValue\"][\"value\"]", + "title": "Cernox in cold tuning system - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-038:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "Cernox in helium tank boTEom", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-039:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "Cernox in helium manifold to he tank", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-030:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "PT100 in Power Coupler - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-031:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "Power Coupler double wall cooling - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-032:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, "max_value": "300" } } ] }, { - "title": "TS2-010CDL:Cryo-TE-82314:MeasValue", + "title": "Cavity 4", "width": 1, "row": { - "4": 23 + "1": 91, + "4": 7, + "7": 7 }, "col": { - "4": 1 + "1": 1, + "4": 4, + "7": 4 }, "col_width": 1, "widgets": [ { "type": "gauge", "settings": { - "value": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82314:MeasValue\"][\"value\"]", + "title": "Cernox in cold tuning system - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-048:MeasValue\"][\"value\"]", "units": "K", - "min_value": "0", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "Cernox in helium tank boTEom", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-049:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "PT100 in Power Coupler - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-041:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, + "max_value": "300" + } + }, + { + "type": "gauge", + "settings": { + "title": "Power Coupler double wall cooling - ECCTD only", + "value": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-042:MeasValue\"][\"value\"]", + "units": "K", + "min_value": 0, "max_value": "300" } } ] }, { - "title": "CrS-TICP:Cryo-TE-31492:Val", - "width": 1, + "title": "Thermal Screens", + "width": 4, "row": { - "4": 23 + "4": 39 }, "col": { - "4": 2 + "4": 1 }, - "col_width": 1, + "col_width": 4, "widgets": [ { - "type": "gauge", + "type": "highcharts-timeseries", "settings": { - "value": "datasources[\"TS2\"][\"CrS-TICP:Cryo-TE-31492:Val\"][\"value\"]", - "units": "K", - "min_value": "0", - "max_value": "300" + "timeframe": 60, + "blocks": 4, + "chartType": "spline", + "xaxis": "{\"title\":{\"text\" : \"Time\"}, \"type\": \"datetime\", \"floor\":0}", + "yaxis": "{\"title\":{\"text\" : \"Values\"}, \"minorTickInterval\":\"auto\", \"floor\":0}", + "series1": "datasources[\"TS2\"][\"CrS-TICP:Cryo-TE-31491:Val\"][\"value\"]", + "series1label": "CrS-TICP:Cryo-TE-31491", + "series2": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82313:MeasValue\"][\"value\"]", + "series2label": "TS2-010CDL:Cryo-TE-82313", + "series3": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82360:MeasValue\"][\"value\"]", + "series3label": "TS2-010CDL:Cryo-TE-82360" + } + }, + { + "type": "highcharts-timeseries", + "settings": { + "timeframe": 60, + "blocks": 4, + "chartType": "spline", + "xaxis": "{\"title\":{\"text\" : \"Time\"}, \"type\": \"datetime\", \"floor\":0}", + "yaxis": "{\"title\":{\"text\" : \"Values\"}, \"minorTickInterval\":\"auto\", \"floor\":0}", + "series1": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-068:MeasValue\"][\"value\"]", + "series1label": "TS2-010CRM:Cryo-TE-068", + "series2": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-064:MeasValue\"][\"value\"]", + "series2label": "TS2-010CRM:Cryo-TE-064", + "series3": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-069:MeasValue\"][\"value\"]", + "series3label": "TS2-010CRM:Cryo-TE-069" + } + }, + { + "type": "highcharts-timeseries", + "settings": { + "timeframe": 60, + "blocks": 4, + "chartType": "spline", + "xaxis": "{\"title\":{\"text\" : \"Time\"}, \"type\": \"datetime\", \"floor\":0}", + "yaxis": "{\"title\":{\"text\" : \"Values\"}, \"minorTickInterval\":\"auto\", \"floor\":0}", + "series1": "datasources[\"TS2\"][\"TS2-010CRM:Cryo-TE-064:MeasValue\"][\"value\"]", + "series1label": "TS2-010CRM:Cryo-TE-064", + "series2": "datasources[\"TS2\"][\"TS2-010CDL:Cryo-TE-82314:MeasValue\"][\"value\"]", + "series2label": "TS2-010CDL:Cryo-TE-82314", + "series3": "datasources[\"TS2\"][\"CrS-TICP:Cryo-TE-31492:Val\"][\"value\"]", + "series3label": "CrS-TICP:Cryo-TE-31492:Val" } } ] @@ -257,7 +338,7 @@ "settings": { "url": "/data/ts2.json", "use_thingproxy": false, - "refresh": 1, + "refresh": 5, "method": "GET" } } diff --git a/WebSites/ts2/index.html b/WebSites/ts2/index.html index b64a5da74bdbe2f0464cd0178bf6155a3f33f7a4..80f75326bfb89bba6f54a3de18fc0b7b996b4260 100644 --- a/WebSites/ts2/index.html +++ b/WebSites/ts2/index.html @@ -46,6 +46,8 @@ "plugins/freeboard/freeboard.widgets.js", "plugins/thirdparty/flot_extended.plugin.js", "plugins/thirdparty/widget.ragIndicator.js", + "plugins/thirdparty/horizontal_linear_gauge.widgets.js", + "plugins/thirdparty/plugin_highcharts.js", "SlickNav/dist/jquery.slicknav.min.js", "examples/plugin_example.js", diff --git a/WebSites/ts2/plugins/thirdparty/horizontal_linear_gauge.widgets.js b/WebSites/ts2/plugins/thirdparty/horizontal_linear_gauge.widgets.js new file mode 100644 index 0000000000000000000000000000000000000000..5eb846aaaed677f15a061573f1b196dacea58392 --- /dev/null +++ b/WebSites/ts2/plugins/thirdparty/horizontal_linear_gauge.widgets.js @@ -0,0 +1,194 @@ +// +// Plugin for horizontal linear gauge +// +// + +(function() { + var gaugeWidget = function (settings) { + var titleElement = $('<h2 class="section-title"></h2>'); + var gaugeElement = $('<div></div>'); + + var self = this; + var paper = null; + var gaugeFill = null; + var width, height; + var valueText, unitsText; + var minValueLabel, maxValueLabel; + //var currentValue = 0; + //var colors = ["#a9d70b", "#f9c802", "#ff0000"]; + + var currentSettings = settings; + + /* get the color for a fill percentage + these colors match the justGage library for radial guagues */ + function getColor(fillPercent) { + // mix colors + // green rgb(169,215,11) #a9d70b + // yellow rgb(249,200,2) #f9c802 + // red rgb(255,0,0) #ff0000 + + if (fillPercent >= 0.5 ) { + fillPercent = 2 * fillPercent - 1; + var R = fillPercent * 255 + (1 - fillPercent) * 249; + var G = fillPercent * 0 + (1 - fillPercent) * 200; + var B = fillPercent * 0 + (1 - fillPercent) * 2; + } + else { + fillPercent = 2 * fillPercent; + var R = fillPercent * 249 + (1 - fillPercent) * 169; + var G = fillPercent * 200 + (1 - fillPercent) * 215; + var B = fillPercent * 2 + (1 - fillPercent) * 11; + } + + return "rgb(" + Math.round(R) + "," + Math.round(G) + "," + Math.round(B) + ")" + } + + self.render = function (element) { + $(element).append(titleElement.html(currentSettings.title)).append(gaugeElement); + + width = gaugeElement.width(); + height = 160; + + var gaugeWidth = 160; + var gaugeHeight = 30; + + paper = Raphael(gaugeElement.get()[0], width, height); + paper.clear(); + + var rect = paper.rect(width / 2 - gaugeWidth / 2, height / 3 - gaugeHeight / 2, gaugeWidth, gaugeHeight); + rect.attr({ + "fill": "#edebeb", + "stroke": "#edebeb" + }); + + // place min and max labels + minValueLabel = paper.text(width / 2 - gaugeWidth / 2 - 8, height / 3, currentSettings.min_value); + maxValueLabel = paper.text(width / 2 + gaugeWidth / 2 + 8, height / 3, currentSettings.max_value); + + minValueLabel.attr({ + "font-family": "arial", + "font-size": "10", + "fill": "#b3b3b3", + "text-anchor": "end" + }); + + maxValueLabel.attr({ + "font-family": "arial", + "font-size": "10", + "fill": "#b3b3b3", + "text-anchor": "start" + }); + + // place units and value + var units = _.isUndefined(currentSettings.units) ? "" : currentSettings.units; + + valueText = paper.text(width / 2, height * 2 / 3, ""); + unitsText = paper.text(width / 2, height * 2 / 3 + 20, units); + + valueText.attr({ + "font-family": "arial", + "font-size": "25", + "font-weight": "bold", + "fill": "#d3d4d4", + "text-anchor": "middle" + }); + + unitsText.attr({ + "font-family": "arial", + "font-size": "10", + "font-weight": "normal", + "fill": "#b3b3b3", + "text-anchor": "middle" + }); + + // fill to 0 percent + gaugeFill = paper.rect(width / 2 - gaugeWidth / 2, height / 3 - gaugeHeight / 2, 0, gaugeHeight); + } + + self.onSettingsChanged = function (newSettings) { + if (newSettings.units != currentSettings.units || newSettings.min_value != currentSettings.min_value || newSettings.max_value != currentSettings.max_value) { + currentSettings = newSettings; + var units = _.isUndefined(currentSettings.units) ? "" : currentSettings.units; + var min = _.isUndefined(currentSettings.min_value) ? 0 : currentSettings.min_value; + var max = _.isUndefined(currentSettings.max_value) ? 0 : currentSettings.max_value; + + unitsText.attr({"text": units}); + minValueLabel.attr({"text": min}); + maxValueLabel.attr({"text": max}); + } + else { + currentSettings = newSettings; + } + + titleElement.html(newSettings.title); + } + + self.onCalculatedValueChanged = function (settingName, newValue) { + if (settingName === "value") { + if (!_.isUndefined(gaugeFill) && !_.isUndefined(valueText)) { + + newValue = _.isUndefined(newValue) ? 0 : newValue; + var fillVal = 160 * (newValue - currentSettings.min_value)/(currentSettings.max_value - currentSettings.min_value); + + fillVal = fillVal > 160 ? 160 : fillVal; + fillVal = fillVal < 0 ? 0 : fillVal; + + var fillColor = getColor(fillVal / 160); + + gaugeFill.animate({"width": fillVal, "fill": fillColor, "stroke": fillColor}, 500, ">"); + valueText.attr({"text": newValue}); + } + } + } + + self.onDispose = function () { + } + + self.getHeight = function () { + return 3; + } + + }; + + freeboard.loadWidgetPlugin({ + type_name: "horizontal-linear-gauge", + display_name: "Horizontal Linear Gauge", + "external_scripts" : [ + "plugins/thirdparty/raphael.2.1.0.min.js", + // "plugins/thirdparty/raphael.2.1.0-custom.js", + "plugins/thirdparty/colormix.2.0.0.min.js" + ], + settings: [ + { + name: "title", + display_name: "Title", + type: "text" + }, + { + name: "value", + display_name: "Value", + type: "calculated" + }, + { + name: "units", + display_name: "Units", + type: "text" + }, + { + name: "min_value", + display_name: "Minimum", + type: "number", + default_value: 0 + }, + { + name: "max_value", + display_name: "Maximum", + type: "number", + default_value: 100 + } + ], + newInstance: function (settings, newInstanceCallback) { + newInstanceCallback(new gaugeWidget(settings)); + } + }); +}()); diff --git a/WebSites/ts2/plugins/thirdparty/plugin_highcharts.js b/WebSites/ts2/plugins/thirdparty/plugin_highcharts.js new file mode 100644 index 0000000000000000000000000000000000000000..d36c89d792e9a6b0d0a079c344a9f23a17738082 --- /dev/null +++ b/WebSites/ts2/plugins/thirdparty/plugin_highcharts.js @@ -0,0 +1,458 @@ +// ┌────────────────────────────────────────────────────────────────────┠\\ +// │ freeboard-dynamic-highcharts-plugin │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ http://blog.onlinux.fr/dynamic-highcharts-plugin-for-freeboard-io/ │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Licensed under the MIT license. │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Freeboard widget plugin for Highcharts. │ \\ +// └────────────────────────────────────────────────────────────────────┘ \\ +(function() { + + // + // DECLARATIONS + // + var HIGHCHARTS_ID = 0; + var ONE_SECOND_IN_MILIS = 1000; + var MAX_NUM_SERIES = 3; + + // + // HELPERS + // + + // Get coordinates of point + function xy(obj, x, y) { + return [obj[x], obj[y]] + } + + function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + // + // TIME SERIES CHARTS + // + var highchartsLineWidgetSettings = [{ + "name": "timeframe", + "display_name": "Timeframe (s)", + "type": "number", + "description": "Specify the last number of seconds you want to see.", + "default_value": 60 + }, { + "name": "blocks", + "display_name": "Height (No. Blocks)", + "type": "number", + "default_value": 4 + }, { + "name": "chartType", + "display_name": "Chart Type", + "type": "option", + "options": [{ + "name": "Area", + "value": "area" + }, { + "name": "Spline", + "value": "spline" + }] + }, { + "name": "title", + "display_name": "Title", + "type": "text" + }, { + "name": "xaxis", + "display_name": "X-Axis", + "type": "calculated", + "default_value": "{\"title\":{\"text\" : \"Time\"}, \"type\": \"datetime\", \"floor\":0}" + }, { + "name": "yaxis", + "display_name": "Y-Axis", + "type": "calculated", + "default_value": "{\"title\":{\"text\" : \"Values\"}, \"minorTickInterval\":\"auto\", \"floor\":0}" + }]; + + for (i = 1; i <= MAX_NUM_SERIES; i++) { + var dataSource = { + "name": "series" + i, + "display_name": "Series " + i + " - Datasource", + "type": "calculated" + }; + + var xField = { + "name": "series" + i + "label", + "display_name": "Series " + i + " - Label", + "type": "text", + }; + + highchartsLineWidgetSettings.push(dataSource); + highchartsLineWidgetSettings.push(xField); + } + + freeboard + .loadWidgetPlugin({ + "type_name": "highcharts-timeseries", + "display_name": "Time series (Highcharts)", + "description": "Time series line chart.", + "external_scripts": [ + "https://code.highcharts.com/highcharts.js", + "https://code.highcharts.com/modules/exporting.js" + ], + "fill_size": true, + "settings": highchartsLineWidgetSettings, + newInstance: function(settings, newInstanceCallback) { + newInstanceCallback(new highchartsTimeseriesWidgetPlugin( + settings)); + } + }); + + var highchartsTimeseriesWidgetPlugin = function(settings) { + + var self = this; + var currentSettings = settings; + + var thisWidgetId = "highcharts-widget-timeseries-" + HIGHCHARTS_ID++; + var thisWidgetContainer = $('<div class="highcharts-widget" id="' + thisWidgetId + '"></div>'); + + function createWidget() { + + Highcharts.theme = { + global: { + useUTC: false + }, + colors: ["#2b908f", "#90ee7e", "#f45b5b", "#7798BF", "#aaeeee", + "#ff0066", "#eeaaee", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee" + ], + chart: { + backgroundColor: null, + style: { + fontFamily: "'Open Sans', sans-serif" + }, + plotBorderColor: '#606063' + }, + plotShadow: false, + title: { + style: { + color: '#E0E0E3', + fontSize: '20px' + } + }, + subtitle: { + style: { + color: '#E0E0E3', + textTransform: 'uppercase' + } + }, + xAxis: { + gridLineColor: '#707073', + labels: { + style: { + color: '#E0E0E3' + } + }, + lineColor: '#707073', + minorGridLineColor: '#505053', + tickColor: '#707073', + title: { + style: { + color: '#A0A0A3' + + } + } + }, + yAxis: { + gridLineColor: '#707073', + labels: { + style: { + color: '#E0E0E3' + } + }, + lineColor: '#707073', + minorGridLineColor: '#505053', + tickColor: '#707073', + tickWidth: 1, + title: { + style: { + color: '#A0A0A3' + } + } + }, + tooltip: { + backgroundColor: 'rgba(0, 0, 0, 0.85)', + style: { + color: '#F0F0F0' + } + }, + plotOptions: { + series: { + dataLabels: { + color: '#B0B0B3' + }, + marker: { + lineColor: '#333' + } + }, + boxplot: { + fillColor: '#505053' + }, + candlestick: { + lineColor: 'white' + }, + errorbar: { + color: 'white' + } + }, + legend: { + itemStyle: { + color: '#E0E0E3' + }, + itemHoverStyle: { + color: '#FFF' + }, + itemHiddenStyle: { + color: '#606063' + } + }, + credits: { + enabled: false, + style: { + color: '#666' + } + }, + labels: { + style: { + color: '#707073' + } + }, + + drilldown: { + activeAxisLabelStyle: { + color: '#F0F0F3' + }, + activeDataLabelStyle: { + color: '#F0F0F3' + } + }, + + navigation: { + buttonOptions: { + symbolStroke: '#DDDDDD', + theme: { + fill: '#505053' + } + } + }, + + // scroll charts + rangeSelector: { + buttonTheme: { + fill: '#505053', + stroke: '#000000', + style: { + color: '#CCC' + }, + states: { + hover: { + fill: '#707073', + stroke: '#000000', + style: { + color: 'white' + } + }, + select: { + fill: '#000003', + stroke: '#000000', + style: { + color: 'white' + } + } + } + }, + inputBoxBorderColor: '#505053', + inputStyle: { + backgroundColor: '#333', + color: 'silver' + }, + labelStyle: { + color: 'silver' + } + }, + + navigator: { + handles: { + backgroundColor: '#666', + borderColor: '#AAA' + }, + outlineColor: '#CCC', + maskFill: 'rgba(255,255,255,0.1)', + series: { + color: '#7798BF', + lineColor: '#A6C7ED' + }, + xAxis: { + gridLineColor: '#505053' + } + }, + + scrollbar: { + barBackgroundColor: '#808083', + barBorderColor: '#808083', + buttonArrowColor: '#CCC', + buttonBackgroundColor: '#606063', + buttonBorderColor: '#606063', + rifleColor: '#FFF', + trackBackgroundColor: '#404043', + trackBorderColor: '#404043' + }, + + // special colors for some of the + legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', + background2: '#505053', + dataLabelsColor: '#B0B0B3', + textColor: '#C0C0C0', + contrastTextColor: '#F0F0F3', + maskColor: 'rgba(255,255,255,0.3)' + }; + + Highcharts.setOptions(Highcharts.theme); + + // Get widget configurations + var thisWidgetXAxis = JSON.parse(currentSettings.xaxis); + var thisWidgetYAxis = JSON.parse(currentSettings.yaxis); + var thisWidgetTitle = currentSettings.title; + var thisWidgetChartType = currentSettings.chartType; + //console.log('chartType:' + currentSettings.chartType + ' ' + thisWidgetChartType); + var thisWidgetSeries = []; + + for (i = 1; i <= MAX_NUM_SERIES; i++) { + var datasource = currentSettings['series' + i]; + if (datasource) { + var serieno = "series" + i + "label"; + var label = currentSettings[serieno]; + console.log('label: ', label); + var newSeries = { + id: 'series' + i, + name: label, + fillColor: { + linearGradient: { + x1: 0, + y1: 0, + x2: 0, + y2: 1 + }, + stops: [ + [0, Highcharts.getOptions().colors[i - 1]], + //[1, 'rgba(2,0,0,0)'] + [1, Highcharts.Color(Highcharts.getOptions().colors[i - 1]).setOpacity(0).get('rgba')] + ] + }, + + data: [], + connectNulls: true + }; + + thisWidgetSeries.push(newSeries); + } + } + + // Create widget + thisWidgetContainer + .css('height', 60 * self.getHeight() - 10 + 'px'); + thisWidgetContainer.css('width', '100%'); + + thisWidgetContainer.highcharts({ + chart: { + type: thisWidgetChartType, + animation: Highcharts.svg, + marginRight: 20 + }, + title: { + text: thisWidgetTitle + }, + xAxis: thisWidgetXAxis, + yAxis: thisWidgetYAxis, + + plotOptions: { + area: { + marker: { + enabled: false, + symbol: 'circle', + radius: 2, + hover: { + enabled: true + } + }, + lineWidth: 2, + states: { + hover: { + lineWidth: 2 + } + }, + threshold: null + } + }, + + tooltip: { + formatter: function() { + return '<b>' + this.series.name + '</b><br/>' + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', + this.x) + '<br/>' + Highcharts.numberFormat(this.y, 1); + } + }, + series: thisWidgetSeries + }); + } + + self.render = function(containerElement) { + $(containerElement).append(thisWidgetContainer); + createWidget(); + } + + self.getHeight = function() { + return currentSettings.blocks; + } + + self.onSettingsChanged = function(newSettings) { + currentSettings = newSettings; + createWidget(); + } + + self.onCalculatedValueChanged = function(settingName, newValue) { + // console.log(settingName, 'newValue:', newValue); + + var chart = thisWidgetContainer.highcharts(); + var series = chart.get(settingName); + if (series) { + var timeframeMS = currentSettings.timeframe * ONE_SECOND_IN_MILIS; + var seriesno = settingName; + var len = series.data.length; + var shift = false; + + // Check if it should shift the series + if (series.data.length > 1) { + + var first = series.data[0].x; + //var last = series.data[series.data.length-1].x; + var last = new Date().getTime(); + // Check if time frame is complete + var diff = last - first; + // console.log('last :', last); + // console.log('first:', first); + // console.log('diff :', diff); + + if (last - first > timeframeMS) { + shift = true; + } + } + + if (isNumber(newValue)) { //check if it is a real number and not text + var x = (new Date()).getTime(); + // console.log('addPoint:', x,currentSettings[seriesno], Number(newValue)); + var plotMqtt = [x, Number(newValue)]; //create the array+ "Y" + series.addPoint(plotMqtt, true, shift); + }; + } + } + + self.onDispose = function() { + return; + } + } + +}());