An experimental swinging needle meter, to play with driving animated SVG from re-frame
Find a file
2020-10-24 18:38:02 +01:00
resources/public 'size' slider on demo page now works correctly! 2020-10-24 17:29:15 +01:00
src Set 'status' to 'stable' 2020-10-24 17:45:09 +01:00
.gitignore Added compiled JavaScript to repository for GitHub pages 2020-10-20 14:44:11 +01:00
index.html OK, Figwheel requires webroot under resources. Bother. 2020-10-20 14:34:26 +01:00
LICENSE Added all the files that I THINK are needed. 2017-06-30 15:12:35 +01:00
project.clj Greatly improved README; upversioned to 1.0.3 2020-10-24 17:16:02 +01:00
README.md Removed unnecessary stuff from Usage in README 2020-10-24 18:38:02 +01:00

swinging-needle-meter

A re-frame application designed to display an example swinging needle meter, as an experiment in animating SVG from re-frame. Draws heavily on re-com.

Works well in Chrome and Firefox; not tested in Internet Exploder.

what it should look like

Demo site

There's a demo site here.

Intended uses

This is a component for a console, typically one controlling a technical or scientific instrument. It is by design flexible and configurable. Minimum value, maximum value, warning value and number of gradations shown are all configurable, as are (obviously) styles.

A cursor will be shown if the value of setpoint is between min-value and max-value; setpoint is a dynamic value which is watched during the run. While the model value is within +- tolerance of the setpoint value, a class target-class is set on the meter indicating an on-target status (by default the frame goes green).

A red-zone may be shown if a warn-value is set which is between min-value and max-value. If such a warn-value is set, then if the current value (model) exceeds warn-value, a class warning-class is set on the meter indicating a warning status (by default the frame goes maroon).

Usage

In your cljs file, require the following:

  (:require [re-frame.core :as rf]
            [swinging-needle-meter.swinging-needle-meter :refer [swinging-needle-meter]])

within a re-com component,

    [swinging-needle-meter
        :model     @(rf/subscribe [:old-value])
        :setpoint  @(rf/subscribe [:setpoint])          ;; optional
        :unit      @(rf/subscribe [:unit])              ;; optional
        :min-value @(rf/subscribe [:min-val])           ;; optional; default 0
        :warn-value @(rf/subscribe [:warn-val])         ;; optional; default 80
        :max-value @(rf/subscribe [:max-val])           ;; optional; default 100
        :tolerance 2                                    ;; optional; default 3
        :alarm-class "snm-warning"                      ;; optional; default "snm-warning"
        :gradations @(rf/subscribe [:gradations])       ;; optional; default 5
        :height    (int (* @(rf/subscribe [:size]) 6))  ;; optional; default 200 (pixels) 
        :width     (int (* @(rf/subscribe [:size]) 10))];; optional; default 300 (pixels)

or, minimally, just

    [swinging-needle-meter
        :model     @(rf/subscribe [:old-value])]

There are further arguments which may be set which are documented here.

Obviously, all the subscriptions above must be registered with re-frame/reg-sub. See re-frame documentation.

The value subscribed to as the value to :model is expected to be a floating point number between that of :min-value and :max-value.

Simulation of a mechanical meter needle with inertia and damping

You don't need animated movement, you can simply jerk the needle to its new position; animation appeals to users who are used to mechanical meters and is easy on the eye, but obviously it means the needle lags a little behind changes in the underlying state.

If you want animation, this is how it works.

The event registered to be driven by :timer in swinging-needle-meter/events.cljs drives the animation of the movement of the needle. The value of :timer is initialised in the state to (js/Date.) in swinging-needle-meter/state.js. Thus, it's a clock that ticks.

The actual value in the state which is tracked by the meter is the value of, in the example, :target. The :timer event moves :old-value progressively towards :target until they coincide. So in a real deployment you'd poll the actual real world value that you were tracking using a repeated asynchronous JSON request, and, on a response to such a request, you would update the value of :target in the state.

Obviously, if you want to put multiple meters onto one page tracking different real world variables, you would minimally have to have a separate key in the state for

  1. The target of each meter;
  2. the old-value of each meter (if animation is desired);

You might also want a separate key for the warn-value of each meter, and possibly also the set-point. Values of other parameters may be subscribed to from values in the state but it will probably be more convenient to hard-wire them or allow them to default.

Development Mode

Run application:

lein clean
lein figwheel dev

Figwheel will automatically push cljs changes to the browser.

Wait a bit, then browse to http://localhost:3449.

Production Build

To compile clojurescript to javascript:

lein clean
lein cljsbuild once min

License

Copyright © 2017 Simon Brooke. Licensed under the GNU General Public License, version 2.0 or (at your option) any later version. If you wish to incorporate parts of this into another open source project which uses a less restrictive license, please contact me; I'm open to dual licensing it.