Anatomy of a widget
- an HTML file used for layout and bindings
- a SCSS file for styles
- a coffeescript file which allows you to handle incoming data & functionality
Number widget's HTML:
<h1 class="title" data-bind="title"></h1>
<h2 class="value" data-bind="current | shortenedNumber | prepend prefix"></h2>
<p class="change-rate">
<i data-bind-class="arrow"></i><span data-bind="difference"></span>
</p>
<p class="more-info" data-bind="moreinfo | raw"></p>
<p class="updated-at" data-bind="updatedAtMessage"></p>
view rawnumber.html hosted with ❤ by GitHub
Widgets use batman bindings in order to update their contents. Whenever the data changes, the DOM will automatically reflect the changes.
You may notice the piping '|' characters in some of the data-bind's above. These are Batman Filters, and let you easily format the representation of data.
Number widget's Coffeescript:
class Dashing.Number extends Dashing.Widget
ready: ->
# This is fired when the widget is done being rendered
onData: (data) ->
# Fired when you receive data
# You could do something like have the widget flash each time data comes in by doing:
# $(@node).fadeOut().fadeIn()
# Any attribute that has the 'Dashing.AnimatedValue' will cause the number to animate when it changes.
@accessor 'current', Dashing.AnimatedValue
# Calculates the % difference between current & last values.
@accessor 'difference', ->
if @get('last')
last = parseInt(@get('last'))
current = parseInt(@get('current'))
if last != 0
diff = Math.abs(Math.round((current - last) / last * 100))
"#{diff}%"
else
""
# Picks the direction of the arrow based on whether the current value is higher or lower than the last
@accessor 'arrow', ->
if @get('last')
if parseInt(@get('current')) > parseInt(@get('last')) then 'icon-arrow-up' else 'icon-arrow-down'
view rawnumber.coffee hosted with ❤ by GitHub
By default, whenever a widget receives JSON data, it mixes in the received data onto itself. This means that if you pass in data with atitle attribute, the widget's title variable will change, and so will all DOM elements bound to it. No need to handle that yourself.
Laying out the widgets
Dashing uses gridster.js to create a layout for your widgets. Each widget is part of an unordered list. The <li> element for a widget contains:
- data-row : What row the widget is on.
- data-col : What column the widget is on
- data-sizex : Integer size for the width of a widget
- data-sizey : Integer size for the height of a widget
For both data-row and data-col, you can leave them as 1, and gridster will automatically position your widgets.
If you want to customize the layout easily, simply navigate to your running dashboard, and drag the widgets with your mouse. You will be prompted to save the layout when you're finished. Follow the on-screen instructions.
For data-sizex and data-sizey, these are multiples of the widget dimensions you can configure in application.coffee
Dashing.on 'ready', ->
Dashing.widget_margins ||= [5, 5]
Dashing.widget_base_dimensions ||= [300, 360]
Dashing.numColumns ||= 4
view rawapplication.coffee hosted with ❤ by GitHub
Getting Data Into Your Widgets
Providing data to widgets is easy. You specify which widget you want using a widget id, and then pass in the JSON data. There are two ways to do this:
Jobs
Dashing uses rufus-scheduler to schedule jobs. You can make a new job with dashing generate job sample_job, which will create a file in the jobs directory called sample_job.rb.
Example
# :first_in sets how long it takes before the job is first run. In this case, it is run immediately
SCHEDULER.every '1m', :first_in => 0 do |job|
send_event('karma', { current: rand(1000) })
end
view rawsample_job.rb hosted with ❤ by GitHub
This job will run every minute, and will send a random number to ALL widgets that have data-id set to 'karma'.
You send data using the following method:
send_event(widget_id, json_formatted_data)
Jobs are where you put stuff such as fetching metrics from a database, or calling a third party API like Twitter. Since the data fetch is happening in only one place, it means that all instances of widgets are in sync. Server Sent Events are used in order to stream data to the dashboards.
Note that if you modify a job then Dashing needs to be restarted to pick up the changes.
API
Your widgets can be updated directly over HTTP. Post the data you want in json to /widgets/widget_id. For security, you will also have to include your auth_token (which can be found in config.ru).
Example
curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "current": 100 }' http://localhost:3030/widgets/karma
view rawpush.sh hosted with ❤ by GitHub
or
HTTParty.post('http://localhost:3030/widgets/karma',
:body => { auth_token: "YOUR_AUTH_TOKEN", current: 1000 }.to_json)
view rawpush.rb hosted with ❤ by GitHub
You can also perform dashboard-level actions by posting to /dashboards/dashboard_id. Currently there is a single event available,reload, that will refresh the target dashboard in the browser.
Example
curl -i -d '{ "auth_token": "YOUR_AUTH_TOKEN", "event": "reload"}' http://localhost:3030/dashboards/sample
view rawcurl.sh hosted with ❤ by GitHub
If you want an event to target every dashboard, use a wildcard (*).
Example
curl -i -d '{ "auth_token": "YOUR_AUTH_TOKEN", "event": "reload"}' http://localhost:3030/dashboards/*
view rawcurl2.sh hosted with ❤ by GitHub
Additional Resources
Check out the wiki for interesting tips such as hosting on Heroku, or adding authentication.
Be sure to look at the list of third party widgets.
Browser Compatibility
Tested in Chrome, Safari 6+, and Firefox 15+.
Does not work in Internet Explorer because it relies on Server Sent Events.
Authors & Maintainers
Contributors
See contributors on GitHub
All contributions are more than welcome; especially new widgets!
License
Dashing is released under the MIT license