diff --git a/README.md b/README.md index f95450d..261d54e 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,18 @@ plugins Plugins for Freeboard.io -## datasource plugins ## +### datasource plugins -- [freeboard.io-node.js](/datasources/plugin_nodejs_sample/README.md) +- [freeboard.io-node.js](/datasources/plugin_nodejs_sample/README.md) (This is a datasource plugin to connect freeboard.io dashboards to real-time node.js servers) -This is a datasource plugin to connect freeboard.io dashboards to real-time node.js servers. \ No newline at end of file +### widget plugins + +- handlebars (author widgets using [handlebars templates](http://handlebarsjs.com)) + - see [starter template](https://github.com/jritsema/freeboard-handlebars-widget) to make things easier + - see [repo](https://github.com/jritsema/freeboard-handlebars) for more info + +- reactjs (author widgets using [react](http://reactjs.com)) + - see [starter template](https://github.com/jritsema/freeboard-react-widget) to make things easier + +- jqplot (author graph/chart based widgets using [jqPlot](http://www.jqplot.com)) + - see [repo](https://github.com/jritsema/freeboard-jqplot) for more info diff --git a/widgets/handlebars-plugin.js b/widgets/handlebars-plugin.js new file mode 100644 index 0000000..7b7ef35 --- /dev/null +++ b/widgets/handlebars-plugin.js @@ -0,0 +1,97 @@ +(function () { + + var handlebarsWidget = function (settings) { + + var self = this; + var htmlElement = $('
'); + var currentSettings = settings; + var template; + + this.render = function (element) { + $(element).append(htmlElement); + } + + this.onSettingsChanged = function (newSettings) { + currentSettings = newSettings; + } + + this.onCalculatedValueChanged = function (settingName, newValue) { + + //helpers need to be registered before compile is called + if (settingName === 'helpers') { + //console.log('registering helpers'); + + //unregister (in case it's already been registered) + Handlebars.unregisterHelper(newValue); + + Handlebars.registerHelper(newValue); + } + + //the template needs to be re-compiled when the view changes + if (settingName === 'view') { + //console.log('view changed'); + + //compile the template + template = Handlebars.compile(newValue); + } + + //the model is injected into the compiled template to be rendered as HTML + if (settingName === 'model') { + //console.log('model changed'); + + //evaluate the handlebars template by executing the template with a context + var html = template(newValue); + htmlElement.html(html); + } + } + + this.onDispose = function () { + } + + this.getHeight = function () { + return Number(currentSettings.height); + } + + this.onSettingsChanged(settings); + }; + + freeboard.loadWidgetPlugin({ + "type_name": "handlebarsWidget", + "display_name": "Handlebars", + "fill_size": true, + "external_scripts": [ + "plugins/thirdparty/handlebars-v2.0.0.js" + ], + "settings": [ + { + "name": "helpers", + "display_name": "Helpers", + "type": "calculated", + "description": "Code that gets passed to Handlebars.registerHelper(). See Handlebars docs." + }, + { + "name": "view", + "display_name": "view", + "type": "calculated", + "description": "HTML view with handlebars template bound to model" + }, + { + "name": "model", + "display_name": "model", + "type": "calculated", + "description": "Model bound to view. Typically an exposed datasource or some code to manipulate data for the view" + }, + { + "name": "height", + "display_name": "Height Blocks", + "type": "number", + "default_value": 4, + "description": "A height block is around 60 pixels" + } + ], + newInstance: function (settings, newInstanceCallback) { + newInstanceCallback(new handlebarsWidget(settings)); + } + }); + +}()); \ No newline at end of file diff --git a/widgets/jqplot-plugin.js b/widgets/jqplot-plugin.js new file mode 100644 index 0000000..ea230a2 --- /dev/null +++ b/widgets/jqplot-plugin.js @@ -0,0 +1,113 @@ +(function () { + + var jqPlotWidget = function (settings) { + + var self = this; + var currentSettings = settings; + var htmlElement; + var data; + var options; + var chartHeight = 300; + var chartWidth = 300; + + //seems to be called once (or after settings change) + this.render = function (element) { + console.log('render'); + + //add external css + $(element).append(''); + + //add the chart div to the dom + var chartDiv = '
'; + console.log(chartDiv); + htmlElement = $(chartDiv); + $(element).append(htmlElement); + } + + this.onSettingsChanged = function (newSettings) { + currentSettings = newSettings; + } + + //seems to be called after render whenever a calculated value changes + this.onCalculatedValueChanged = function (settingName, newValue) { + console.log('onCalculatedValueChanged for ' + settingName); + + if (settingName == 'data') + data = newValue; + + if (settingName == 'options') + options = newValue; + + //render the chart + htmlElement.empty(); + $.jqplot(currentSettings.id, data, options); + } + + this.onDispose = function () { + } + + this.getHeight = function () { + return Number(currentSettings.height); + } + + this.onSettingsChanged(settings); + }; + + freeboard.loadWidgetPlugin({ + "type_name": "jqPlotWidget", + "display_name": "jqPlot", + "fill_size": true, + "external_scripts": [ + "http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/jquery.jqplot.min.js", + "http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.pieRenderer.min.js", + "http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.barRenderer.min.js", + "http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.categoryAxisRenderer.min.js", + "http://cdnjs.cloudflare.com/ajax/libs/jqPlot/1.0.8/plugins/jqplot.pointLabels.min.js" + ], + "settings": [ + { + "name": "id", + "display_name": "id", + "default_value": "chart1", + "description": "dom element id of the chart (must be unique for multiple charts)" + }, + { + "name": "data", + "display_name": "Chart Data", + "type": "calculated", + "description": "The data to plot" + }, + { + "name": "options", + "display_name": "Chart Options", + "type": "calculated", + "description": "js object containing jqPlot options for chart" + }, + { + "name": "chartHeight", + "display_name": "Chart Height (px)", + "type": "number", + "default_value": 300, + "description": "chart height in pixels" + }, + { + "name": "chartWidth", + "display_name": "Chart Widgth (px)", + "type": "number", + "default_value": 300, + "description": "chart width in pixels" + }, + { + "name": "height", + "display_name": "Height Blocks", + "type": "number", + "default_value": 5, + "description": "A height block is around 60 pixels" + } + ], + newInstance: function (settings, newInstanceCallback) { + newInstanceCallback(new jqPlotWidget(settings)); + } + }); + +}()); \ No newline at end of file diff --git a/widgets/react-plugin.js b/widgets/react-plugin.js new file mode 100644 index 0000000..58bff22 --- /dev/null +++ b/widgets/react-plugin.js @@ -0,0 +1,75 @@ +(function () { + + var ReactWidget = function (settings) { + + var self = this; + var currentSettings = settings; + var mountPoint; + var reactClass; + var data; + + this.render = function (element) { + mountPoint = element; + } + + this.onSettingsChanged = function (newSettings) { + currentSettings = newSettings; + } + + this.onCalculatedValueChanged = function (settingName, newValue) { + + if (settingName === 'data') { + data = newValue; + } + + if (settingName === 'code') { + reactClass = newValue; + } + + React.render(React.createElement(reactClass, { data: data }), mountPoint); + } + + this.onDispose = function () { + } + + this.getHeight = function () { + return Number(currentSettings.height); + } + + this.onSettingsChanged(settings); + }; + + freeboard.loadWidgetPlugin({ + "type_name": "ReactWidget", + "display_name": "React", + "fill_size": true, + "external_scripts": [ + "plugins/thirdparty/react-0.12.2.js" + ], + "settings": [ + { + "name": "code", + "display_name": "Component", + "type": "calculated", + "description": "" + }, + { + "name": "data", + "display_name": "Data", + "type": "calculated", + "description": "" + }, + { + "name": "height", + "display_name": "Height Blocks", + "type": "number", + "default_value": 4, + "description": "A height block is around 60 pixels" + } + ], + newInstance: function (settings, newInstanceCallback) { + newInstanceCallback(new ReactWidget(settings)); + } + }); + +}()); \ No newline at end of file