Compare commits
21 commits
Author | SHA1 | Date | |
---|---|---|---|
|
6a889b247e | ||
|
fdffaa0c92 | ||
|
4ae79d3bae | ||
|
9c335ca453 | ||
|
7020fa4203 | ||
|
293e911556 | ||
|
e3b5963e55 | ||
|
642662cc82 | ||
|
e9e3dd6a8d | ||
|
dc226b1f25 | ||
|
3d5a2fb322 | ||
|
636e6466c0 | ||
|
ec9a0803f4 | ||
|
26a60fb1fe | ||
|
4468c155d3 | ||
|
57b8abf0d3 | ||
|
45865eaae2 | ||
|
ef4653e3b2 | ||
|
689f1b108c | ||
|
832a3eb2db | ||
|
589dbbb36b |
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,7 +1,5 @@
|
|||
/*.log
|
||||
/target
|
||||
/*-init.clj
|
||||
/resources/public/js/compiled
|
||||
out
|
||||
|
||||
resources/public/vendor/*
|
||||
|
|
64
README.md
64
README.md
|
@ -6,6 +6,10 @@ Works well in Chrome and Firefox; not tested in Internet Exploder.
|
|||
|
||||

|
||||
|
||||
## Demo site
|
||||
|
||||
There's a demo site [here](https://simon-brooke.github.io/swinging-needle-meter/resources/public/index.html).
|
||||
|
||||
## Intended uses
|
||||
|
||||
This is a component for a console, typically one controlling a technical or scientific instrument. It is
|
||||
|
@ -16,6 +20,63 @@ A cursor will be shown if the value of *setpoint* is between *min-value* and *ma
|
|||
|
||||
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:
|
||||
|
||||
```clojure
|
||||
(:require [re-frame.core :as rf]
|
||||
[swinging-needle-meter.swinging-needle-meter :refer [swinging-needle-meter]])
|
||||
```
|
||||
|
||||
within a [re-com](https://github.com/day8/re-com) component,
|
||||
|
||||
```clojure
|
||||
[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
|
||||
|
||||
```clojure
|
||||
[swinging-needle-meter
|
||||
:model @(rf/subscribe [:old-value])]
|
||||
```
|
||||
|
||||
There are further arguments which may be set which are documented
|
||||
[here](https://simon-brooke.github.io/swinging-needle-meter/resources/public/index.html#parameters).
|
||||
|
||||
Obviously, all the subscriptions above must be registered with `re-frame/reg-sub`. See [re-frame documentation](http://day8.github.io/re-frame/re-frame/).
|
||||
|
||||
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:
|
||||
|
@ -31,7 +92,6 @@ Wait a bit, then browse to [http://localhost:3449](http://localhost:3449).
|
|||
|
||||
## Production Build
|
||||
|
||||
|
||||
To compile clojurescript to javascript:
|
||||
|
||||
```
|
||||
|
@ -42,5 +102,5 @@ 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 Smeagol into another open source project which uses a less restrictive
|
||||
parts of this into another open source project which uses a less restrictive
|
||||
license, please contact me; I'm open to dual licensing it.
|
||||
|
|
24
index.html
Normal file
24
index.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta http-equiv="refresh" content="0; URL='resources/public/index.html'" />
|
||||
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="resources/public/css/re-com.css">
|
||||
<link rel="stylesheet" href="resources/public/css/swinging-needle-meter.css">
|
||||
<link href="http://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic" rel="stylesheet" type="text/css">
|
||||
<link href="http://fonts.googleapis.com/css?family=Roboto+Condensed:400,300" rel="stylesheet" type="text/css">
|
||||
|
||||
<title>Example swinging needle meter following re-com conventions.</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h1>
|
||||
This isn't actually where you want to be.
|
||||
</h1>
|
||||
<p>
|
||||
If you're seeing this, you probably want to <a href="resources/public/index.html">go here.</a>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,4 +1,4 @@
|
|||
(defproject swinging-needle-meter "1.0.0"
|
||||
(defproject swinging-needle-meter "1.0.3"
|
||||
:description "A swinging needle meter, as an experiment in animating SVG from re-frame. Draws heavily on re-com."
|
||||
:dependencies [[org.clojure/clojure "1.8.0"]
|
||||
[org.clojure/clojurescript "1.9.229"]
|
||||
|
|
|
@ -26,7 +26,7 @@ html, body {
|
|||
letter-spacing: 0.002em;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
padding: 0px 5%;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------
|
||||
|
|
282
resources/public/css/standard.css
Normal file
282
resources/public/css/standard.css
Normal file
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Standard.css copied from Smeagol: a very simple Wiki engine
|
||||
* Copyright (C) 2014 Simon Brooke
|
||||
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
/* ids generally in document order */
|
||||
|
||||
/* top-of-page navigation, not editable, provided by Smeagol */
|
||||
#nav{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
_position: absolute;
|
||||
_top: expression(document.documentElement.scrollTop);
|
||||
z-index: 149;
|
||||
background:rgba(40, 40, 40,0.8);
|
||||
}
|
||||
|
||||
#user {
|
||||
font-height: 66%;
|
||||
float: right;
|
||||
padding: 0.1em 0.75em;
|
||||
margin: 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#user a {
|
||||
color: silver;
|
||||
}
|
||||
|
||||
/* only needed for fly-out menu effect on tablet and phone stylesheets */
|
||||
#nav-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#nav-menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#nav ul li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#nav ul li a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
padding: 0.1em 0.75em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#nav ul li.active a { background: silver;}
|
||||
li.nav-item a:hover { background: rgb( 240, 240, 240) }
|
||||
li.nav-item a:active { background: gray; color: white; }
|
||||
|
||||
/* header for all pages in the Wiki - editable, provided by users. Within main-container */
|
||||
#header {
|
||||
margin-top: 0;
|
||||
width:100%;
|
||||
background-color: gray;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* left bar for all pages in the Wiki - editable, provided by users. Within main-container */
|
||||
#left-bar {
|
||||
width: 17%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* content of the current in the Wiki - editable, provided by users. Within main-container */
|
||||
#content {
|
||||
border: thin solid silver;
|
||||
width: 80%;
|
||||
float: right;
|
||||
padding-bottom: 5em;
|
||||
}
|
||||
|
||||
/* cookies information box, fixed, in right margin, just above footer */
|
||||
#cookies {
|
||||
width: 30%;
|
||||
float: right;
|
||||
position: fixed;
|
||||
bottom: 1.5em;
|
||||
right: 0;
|
||||
z-index: 150;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* about-cookies box: permanently visible part of cookies information box */
|
||||
#about-cookies {
|
||||
clear: right;
|
||||
width: 10em;
|
||||
font-size: 66%;
|
||||
float: right;
|
||||
text-align: right;
|
||||
padding: 0.25em 2em;
|
||||
color: white;
|
||||
background:rgba(40,40,40,0.8);
|
||||
}
|
||||
|
||||
/* more-about-cookies box, normally hidden */
|
||||
#more-about-cookies {
|
||||
display: none;
|
||||
padding: 0.25em 2em;
|
||||
color: white;
|
||||
background:rgba(40,40,40,0.8);
|
||||
border-bottom: thin solid white;
|
||||
}
|
||||
|
||||
/* but magically appears on mouseover */
|
||||
#cookies:hover #more-about-cookies {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* footer of the page - not-editable, provided by Smeagol */
|
||||
#footer {
|
||||
clear: both;
|
||||
font-size: smaller;
|
||||
text-align: center;
|
||||
color:white;
|
||||
background:rgba(128,128,128,0.95);
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0.25em 0;
|
||||
bottom:0;
|
||||
position:fixed;
|
||||
vertical-align: top;
|
||||
z-index:150;
|
||||
_position:absolute;
|
||||
_top: expression(eval(document.documentElement.scrollTop+
|
||||
(document.documentElement.clientHeight-this.offsetHeight)));
|
||||
}
|
||||
|
||||
|
||||
.change {
|
||||
background-color: rgb( 223, 223, 223);
|
||||
border: thin solid silver;
|
||||
}
|
||||
|
||||
|
||||
.error {
|
||||
width: 100%;
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.message {
|
||||
border: thin solid red;
|
||||
}
|
||||
|
||||
.minor-controls {
|
||||
width: 10em;
|
||||
float: right;
|
||||
padding: 0.25em 2em;
|
||||
color: white;
|
||||
background:rgba(40,40,40,0.8);
|
||||
font-size: 66%;
|
||||
}
|
||||
|
||||
.minor-controls a {
|
||||
float: right;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.warn {
|
||||
color: maroon;
|
||||
}
|
||||
|
||||
.widget {
|
||||
background-color: silver;
|
||||
border: thin solid white;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wiki {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form {
|
||||
border: thin solid silver;
|
||||
}
|
||||
|
||||
del {
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.content, form, p, pre, h1, h2, h3, h4, h5 {
|
||||
padding: 0.25em 5%;
|
||||
}
|
||||
|
||||
dl, menu, ol, table, ul {
|
||||
margin: 0.25em 5%;
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
input.action {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
input.action-dangerous {
|
||||
color: white;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
input.required:after {
|
||||
content: " \*";
|
||||
color: red;
|
||||
}
|
||||
|
||||
ins {
|
||||
color: green;
|
||||
}
|
||||
|
||||
label {
|
||||
width: 20%;
|
||||
min-width: 20em;
|
||||
border-right: thin solid gray;
|
||||
}
|
||||
|
||||
menu li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
menu li::before {
|
||||
content: "|| ";
|
||||
}
|
||||
|
||||
table {
|
||||
border: 2px solid black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.music-ruled tr:nth-child(odd) {
|
||||
background-color: silver;
|
||||
}
|
||||
|
||||
th, td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding: 0.15em 1.5em;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: silver;
|
||||
}
|
||||
|
BIN
resources/public/favicon.ico
Normal file
BIN
resources/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
BIN
resources/public/images/credits/cljs-icon.png
Normal file
BIN
resources/public/images/credits/cljs-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7 KiB |
BIN
resources/public/images/credits/clojure-icon.gif
Normal file
BIN
resources/public/images/credits/clojure-icon.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
resources/public/images/credits/github-logo-transparent.png
Normal file
BIN
resources/public/images/credits/github-logo-transparent.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.7 KiB |
BIN
resources/public/images/credits/gnu.small.png
Normal file
BIN
resources/public/images/credits/gnu.small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
|
@ -3,19 +3,35 @@
|
|||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="vendor/css/material-design-iconic-font.min.css">
|
||||
<link rel="stylesheet" href="css/re-com.css">
|
||||
<link rel="stylesheet" href="css/standard.css">
|
||||
<link rel="stylesheet" href="css/swinging-needle-meter.css">
|
||||
<link href="http://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic" rel="stylesheet" type="text/css">
|
||||
<link href="http://fonts.googleapis.com/css?family=Roboto+Condensed:400,300" rel="stylesheet" type="text/css">
|
||||
|
||||
|
||||
<title>Example swinging needle meter following re-com conventions.</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="app">
|
||||
<h1>
|
||||
Please be patient...
|
||||
</h1>
|
||||
<p>
|
||||
If you're seeing this, Javascript has not yet loaded. If you continue
|
||||
to see this for more than a minute, it may be that something has broken.
|
||||
</p>
|
||||
</div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js"></script>
|
||||
<script src="js/compiled/app.js"></script>
|
||||
<script>swinging_needle_meter.core.init();</script>
|
||||
<footer>
|
||||
<div id="credits">
|
||||
<div>
|
||||
<img height="16" width="16" alt="ClojureScript" src="images/credits/cljs-icon.png"/> Powered by <a href="http://clojurescript.org">ClojureScript</a> ||
|
||||
<img height="16" width="16" alt="GitHub" src="images/credits/github-logo-transparent.png"/>Find me/fork me on <a href="https://github.com/simon-brooke/swinging-needle-meter">Github</a> ||
|
||||
<img height="16" width="16" alt="Free Software Foundation" src="images/credits/gnu.small.png"/>Licensed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License version 2.0</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
|
683
resources/public/js/compiled/app.js
Normal file
683
resources/public/js/compiled/app.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,10 +1,9 @@
|
|||
(ns swinging-needle-meter.swinging-needle-meter
|
||||
(:require [clojure.string :as string]
|
||||
[re-com.core :refer [h-box v-box box gap line label title slider checkbox p]]
|
||||
[re-com.core :refer [box]]
|
||||
[re-com.box :refer [flex-child-style]]
|
||||
[re-com.util :refer [deref-or-value]]
|
||||
[re-com.validate :refer [number-or-string? css-style? html-attr? validate-args-macro]]
|
||||
[reagent.core :as reagent]
|
||||
[swinging-needle-meter.utils :refer [abs]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -27,7 +26,7 @@
|
|||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2014 Simon Brooke
|
||||
;;;; Copyright (C) 2017 Simon Brooke
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
@ -87,7 +86,6 @@
|
|||
;; from the left end of the scale to right end, in degrees.
|
||||
(def full-scale-deflection 140)
|
||||
|
||||
|
||||
(defn deflection
|
||||
"Return the linear deflection of a needle given this `value` on the
|
||||
range `min-value`...`max-value`."
|
||||
|
@ -97,7 +95,6 @@
|
|||
limited (min (max (+ zero-offset (/ value range)) 0) 1)]
|
||||
(* (- limited 0.5) full-scale-deflection)))
|
||||
|
||||
|
||||
(defn polar-to-cartesian
|
||||
"Return, as a map with keys :x. :y, the cartesian coordinates at the point
|
||||
`radius` distance at `theta` (degrees) angle from a point at
|
||||
|
@ -108,7 +105,6 @@
|
|||
{:x (+ cx (* radius (.cos js/Math in-radians)))
|
||||
:y (+ cy (* radius (.sin js/Math in-radians)))}))
|
||||
|
||||
|
||||
(defn describe-arc
|
||||
"Return as a string an SVG path definition describing an arc centred
|
||||
at `cx`, cy` starting at `start-angle` and ending at `end-angle` (both
|
||||
|
@ -121,7 +117,6 @@
|
|||
sweep (if (> end-angle start-angle) 1 0)]
|
||||
(string/join " " ["M" (:x start) (:y start) "A" radius radius 0 large-arc? sweep (:x end) (:y end)])))
|
||||
|
||||
|
||||
(defn as-label
|
||||
"If this arg is a floating point number, format it to a reasonable width; else return it."
|
||||
[arg]
|
||||
|
@ -130,7 +125,6 @@
|
|||
(.toFixed arg 2)
|
||||
arg))
|
||||
|
||||
|
||||
(defn gradation
|
||||
"Return as a string an SVG path definition describing a radial stroke from a center
|
||||
at `cx`, cy` starting at `min-radius` and extending to `max-radius`."
|
||||
|
@ -151,13 +145,6 @@
|
|||
:x cx
|
||||
:y (- cy min-radius)} (as-label label)]])
|
||||
|
||||
|
||||
(defn as-mm
|
||||
"return the argument, as a string, with 'mm' appended"
|
||||
[arg]
|
||||
(str arg "mm"))
|
||||
|
||||
|
||||
(defn swinging-needle-meter
|
||||
"Render an SVG swinging needle meter"
|
||||
[& {:keys [model setpoint width height min-value max-value warn-value tolerance class gradations alarm-class cursor-class frame-class hub-class needle-class redzone-class scale-class target-class unit id style attr]
|
||||
|
@ -181,7 +168,6 @@
|
|||
{:pre [(validate-args-macro swinging-needle-args-desc args "swinging-needle")]}
|
||||
(let [model (deref-or-value model)
|
||||
setpoint (deref-or-value setpoint)
|
||||
mid-point-deflection (/ full-scale-deflection 2)
|
||||
cx (/ width 2)
|
||||
cy (* height 0.90)
|
||||
needle-length (* height 0.75)
|
||||
|
@ -217,7 +203,7 @@
|
|||
:y (/ height 2)
|
||||
:width "100"
|
||||
:id (str id "-current-value")
|
||||
:class "snm-value"}[:tspan (str (as-label model) (if unit " ") unit)]]
|
||||
:class "snm-value"}[:tspan (str (as-label model) (when unit " ") unit)]]
|
||||
[:path {:class scale-class
|
||||
:id (str id "-scale")
|
||||
:d (describe-arc cx cy scale-radius
|
||||
|
@ -237,7 +223,7 @@
|
|||
:id (str id "-needle")
|
||||
:d (str "M " cx "," (- cy needle-length) " " cx "," cy) ;; "M cx,20 cx,100"
|
||||
:transform (str "rotate( " (deflection model min-value max-value) "," cx "," cy ")") }]
|
||||
(if (> gradations 0)
|
||||
(when (> gradations 0)
|
||||
(apply vector (cons :g (map #(let
|
||||
[value (+ min-value
|
||||
(*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(ns swinging-needle-meter.utils
|
||||
(:require [re-com.core :refer [h-box v-box box gap title line label hyperlink-href align-style]]))
|
||||
(:require [re-com.core :refer [h-box v-box gap title line label hyperlink-href align-style]]))
|
||||
|
||||
;;;; This file is mostly stolen wholesale from re-demo in the re-com package;
|
||||
;;;; I claim no credit for it.
|
||||
|
|
|
@ -1,25 +1,40 @@
|
|||
(ns swinging-needle-meter.views
|
||||
(:require [re-frame.core :as rf]
|
||||
[re-com.core :refer [h-box v-box box gap line label title progress-bar slider checkbox p single-dropdown]]
|
||||
[re-com.util :refer [deref-or-value]]
|
||||
[re-com.core :refer [h-box v-box box label title slider p single-dropdown]]
|
||||
[swinging-needle-meter.swinging-needle-meter :refer [swinging-needle-meter swinging-needle-args-desc]]
|
||||
[swinging-needle-meter.utils :refer [panel-title title2 args-table github-hyperlink status-text]]
|
||||
[reagent.core :as reagent]
|
||||
[swinging-needle-meter.utils :refer [abs]]))
|
||||
[swinging-needle-meter.utils :refer [panel-title title2 args-table status-text]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; swinging-needle-meter: an experiment in animating SVG from re-frame.
|
||||
;;;; Draws heavily on re-com..
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2017 Simon Brooke
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; ------------------------------------------------------------------------------------
|
||||
;; Demo: swinging-needle-meter
|
||||
;; ------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
(defn swinging-needle-demo
|
||||
[]
|
||||
(let [unit @(rf/subscribe [:unit])
|
||||
min-val @(rf/subscribe [:min-val])
|
||||
max-val @(rf/subscribe [:max-val])
|
||||
warn-val @(rf/subscribe [:warn-val])
|
||||
gradations @(rf/subscribe [:gradations])
|
||||
size @(rf/subscribe [:size])]
|
||||
(let [size @(rf/subscribe [:size])]
|
||||
(fn
|
||||
[]
|
||||
[v-box
|
||||
|
@ -32,7 +47,7 @@
|
|||
:gap "10px"
|
||||
:width "450px"
|
||||
:children [[title2 "Notes"]
|
||||
[status-text "Wildly experimental"]
|
||||
[status-text "Stable"]
|
||||
[p "An SVG swinging needle meter intended to be useful in dashboards."]
|
||||
[p "Note that the cursor will vanish if the setpoint is null or is less than or equal to min-value; this is intentional."]
|
||||
[p "Note that if the value of model is lower then min-value or greater than max-value,
|
||||
|
@ -54,7 +69,8 @@
|
|||
value, the class target-class will be set on the meter to indicate an on-target status. The setpoint value, like the model value,
|
||||
may change dynamically at run-time."]
|
||||
|
||||
[args-table swinging-needle-args-desc]]]
|
||||
[:a {:name "parameters"}
|
||||
[args-table swinging-needle-args-desc]]]]
|
||||
[v-box
|
||||
:gap "10px"
|
||||
:children [[title2 "Demo"]
|
||||
|
@ -148,12 +164,12 @@
|
|||
:gap "10px"
|
||||
:children [[box :align :start :child [:code ":size"]]
|
||||
[slider
|
||||
:model size
|
||||
:model @(rf/subscribe [:size])
|
||||
:min 25
|
||||
:max 100
|
||||
:width "200px"
|
||||
:on-change #(rf/dispatch [:set-size %])]
|
||||
[label :label size]]]
|
||||
[label :label @(rf/subscribe [:size])]]]
|
||||
]]]]]]]])))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue