Skip to content

Instantly share code, notes, and snippets.

@erikvullings
Last active February 18, 2023 10:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erikvullings/17200a0f1ddb5cdd1da2673d88efecb1 to your computer and use it in GitHub Desktop.
Save erikvullings/17200a0f1ddb5cdd1da2673d88efecb1 to your computer and use it in GitHub Desktop.
Gauge

A simple gauge like control. For an animated example, see here (the animation was added by pygy).

Inputs are:

  • colors: an array of strings representing category colors. The more colors you specify, the more categories there will be.
  • margin: in pixels around the SVG
  • r1 and r2: the inner and outer radius in pixels (default 80 and 140, respectively)
  • valueInDegrees: the value of the gauge meter in degrees [0-180], default 0.
  • arrowColor: color of the gauge meter, default grey.
  • arrowThickness: base width of the gauge meter, in pixels, default 8.

image

const root = document.body;
const Gauge = () => {
return {
view: ({
attrs: {
/** Category colors */
colors = ["#fde7d0ff", "#fec48dff", "#fe952aff", "#e27000ff"],
/** Margin around the gauge */
margin = 10,
/** Inner radius */
r1 = 80,
/** Outer radius */
r2 = 140,
/** Value in degrees [0-180] of the gauge meter */
valueInDegrees = 0,
/** Color of the gauge meter */
arrowColor = "grey",
/** Base width of the gauge meter */
arrowThickness = 8,
},
}) => {
const arrow = r2 - arrowThickness;
const count = colors.length;
const width = 2 * (r2 + margin);
const height = r2 + 2 * margin;
const [x0, y0] = [r2 + margin, r2 + margin];
const alpha = Math.PI / count;
const slices = [];
let sinA0 = 0;
let cosA0 = 1;
let angle = alpha;
for (let i = 0; i < count; i++) {
let sinA1 = Math.sin(angle);
let cosA1 = Math.cos(angle);
const d = `
M ${x0 - r1 * cosA0} ${y0 - r1 * sinA0}
A ${r1} ${r1} 0 0 1 ${x0 - r1 * cosA1} ${y0 - r1 * sinA1}
L ${x0 - r2 * cosA1} ${y0 - r2 * sinA1}
A ${r2} ${r2} 0 0 0 ${x0 - r2 * cosA0} ${y0 - r2 * sinA0}
Z
`;
sinA0 = sinA1;
cosA0 = cosA1;
angle += alpha;
slices.push(d);
}
return m("svg[xmlns=http://www.w3.org/2000/svg]", { width, height }, [
slices.map((d, i) => m("path", { d, fill: colors[i] })),
m("path", {
d: `M ${x0 - arrow} ${y0} L ${x0} ${y0 - arrowThickness} L ${x0} ${
y0 + arrowThickness
} Z`,
fill: arrowColor,
transform: `rotate(${valueInDegrees} ${x0} ${y0})`,
}),
]);
},
};
};
const eachFrame = cb => {
cb()
requestAnimationFrame(() => eachFrame(cb))
}
let x = 0;
eachFrame(() => {
x += 0.02
const angle = 90 * (1 + Math.sin(x))
m.render(root, m(Gauge, {
colors: ['#fde7d0ff', '#fec48dff', '#fe952aff', '#e27000ff'],
margin: 10,
r1: 80,
r2: 140,
arrowThickness: 8,
valueInDegrees: angle
}));
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment