Four small gauges in one circle: each quarter is its own arc with its own scale, color and needle, so one chart shows four readings side by side.
Splitting one circle into parts gives each reading its own scale while keeping them together, so one look covers all four. It suits readings that always go together, like the vital signs of a machine. Each part is short, so keep the scales simple.
Built with amCharts 5, a JavaScript library. The JavaScript includes your theme and renderer (canvas or SVG); the JSON also follows the changes you make with the controls.
npm install @amcharts/amcharts5. See Getting started.
The same chart as a JSON config. Chart Maker reads and writes this format, the library's JSON parser turns it into a chart, and the <am5-chart> element puts it on a page with no code."type" is the class to create and "settings" what you would pass to its new() in code; "properties" fill in its parts, lists such as series and axes or templates such as columns.template; "refs" holds objects used in more than one place ("#series-0" stands for the one named series-0); a string starting with "@" takes a value from another object, such as "@series.get('fill')".
A complete page. Save it as an .html file and open it in a browser.
Paste this into an AI coding assistant to build the chart from scratch. More in amCharts & AI.
// Create root and chart
var root = am5.Root.new("chartdiv");
root.setThemes([
am5themes_Animated.new(root),
am5themes_Responsive.new(root)
]);
var chart = root.container.children.push(
am5radar.RadarChart.new(root, {
panX: false, // no dragging to pan...
panY: false, // ...in either direction
radius: am5.percent(90), // the gauge fills 90% of the space
// a negative number is pixels in from the outer edge: the scales are a 20px band
innerRadius: -20
})
);
// colors come from the theme, every second one so the four parts differ clearly
var colors = am5.ColorSet.new(root, { step: 2 });
// one scale: a value axis on an arc of its own, filled with its color
function createAxis(min, max, start, end, color) {
var axisRenderer = am5radar.AxisRendererCircular.new(root, {
strokeOpacity: 0.1, // a faint line along the arc
minGridDistance: 30, // at least 30px between the labels along the arc
startAngle: start, // where this scale's arc begins...
endAngle: end, // ...and ends
stroke: color // in the part's color
});
axisRenderer.ticks.template.setAll({
visible: true, // ticks at the labels...
strokeOpacity: 0.8, // ...nearly solid...
stroke: color // ...in the part's color
});
axisRenderer.grid.template.setAll({
visible: false // no grid lines across the gauge
});
var axis = chart.xAxes.push(
am5xy.ValueAxis.new(root, {
maxDeviation: 0, // the scale never pans past its ends
min: min,
max: max,
strictMinMax: true, // exactly min to max, not rounded to nicer numbers
renderer: axisRenderer
})
);
// a range over the whole scale fills the axis's arc with its color
var rangeDataItem = axis.makeDataItem({
value: min,
endValue: max
});
var range = axis.createAxisRange(rangeDataItem);
rangeDataItem.get("axisFill").setAll({
visible: true, // show the range's fill...
fill: color, // ...in the part's color...
fillOpacity: 0.8, // ...nearly solid...
stroke: color, // ...with an outline in the same color
strokeOpacity: 0.8,
strokeWidth: 1
});
rangeDataItem.get("tick").setAll({
visible: false // no tick of its own for the range
});
return axis;
}
// a hand on the given scale, in the scale's color
function createHand(axis) {
var color = axis.get("renderer").get("stroke"); // the scale's color
var handDataItem = axis.makeDataItem({
value: 0 // the hand starts at 0
});
var hand = handDataItem.set("bullet", am5xy.AxisBullet.new(root, {
// a short hand near the rim, from 70% to 90% of the radius
sprite: am5radar.ClockHand.new(root, {
radius: am5.percent(90),
innerRadius: am5.percent(70)
})
}));
hand.get("sprite").pin.setAll({
forceHidden: true // no round pin in the middle
});
hand.get("sprite").hand.setAll({
fill: color, // the hand in the scale's color...
fillOpacity: 0.9 // ...nearly solid
});
axis.createAxisRange(handDataItem); // the hand follows this data item's value
return hand;
}
// four scales, each on an 80-degree arc of its own, with 10-degree gaps between them
var axis1 = createAxis(0, 100, -85, -5, colors.next());
var axis2 = createAxis(0, 200, 5, 85, colors.next());
var axis3 = createAxis(0, 20, 95, 175, colors.next());
var axis4 = createAxis(0, 100, 185, 265, colors.next());
var hand1 = createHand(axis1);
var hand2 = createHand(axis2);
var hand3 = createHand(axis3);
var hand4 = createHand(axis4);
// every 2 seconds, each hand swings to a random value on its scale
setInterval(function() {
hand1.get("sprite").dataItem.animate({
key: "value",
to: Math.random() * hand1.axis.get("max"), // anywhere from 0 to the scale's max
duration: 800, // 0.8 seconds...
easing: am5.ease.out(am5.ease.cubic) // ...slowing down at the end
});
hand2.get("sprite").dataItem.animate({
key: "value",
to: Math.random() * hand2.axis.get("max"),
duration: 800,
easing: am5.ease.out(am5.ease.cubic)
});
hand3.get("sprite").dataItem.animate({
key: "value",
to: Math.random() * hand3.axis.get("max"),
duration: 800,
easing: am5.ease.out(am5.ease.cubic)
});
hand4.get("sprite").dataItem.animate({
key: "value",
to: Math.random() * hand4.axis.get("max"),
duration: 800,
easing: am5.ease.out(am5.ease.cubic)
});
}, 2000);
{
"type": "RadarChart",
"settings": {
"panX": false,
"panY": false,
"radius": {
"type": "Percent",
"value": 90
},
"innerRadius": -20
},
"properties": {
"xAxes": [
"#axis-0",
"#axis-1",
"#axis-2",
"#axis-3"
]
},
"refs": [
{
"axis-0": {
"type": "ValueAxis",
"settings": {
"maxDeviation": 0,
"min": 0,
"max": 100,
"strictMinMax": true,
"renderer": {
"type": "AxisRendererCircular",
"settings": {
"strokeOpacity": 0.1,
"minGridDistance": 30,
"startAngle": -85,
"endAngle": -5,
"stroke": {
"type": "Color",
"value": "#67b7dc"
}
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"visible": false
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"visible": true,
"strokeOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#67b7dc"
}
}
}
}
}
}
}
}
}
},
{
"axis-1": {
"type": "ValueAxis",
"settings": {
"maxDeviation": 0,
"min": 0,
"max": 200,
"strictMinMax": true,
"renderer": {
"type": "AxisRendererCircular",
"settings": {
"strokeOpacity": 0.1,
"minGridDistance": 30,
"startAngle": 5,
"endAngle": 85,
"stroke": {
"type": "Color",
"value": "#6771dc"
}
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"visible": false
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"visible": true,
"strokeOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#6771dc"
}
}
}
}
}
}
}
}
}
},
{
"axis-2": {
"type": "ValueAxis",
"settings": {
"maxDeviation": 0,
"min": 0,
"max": 20,
"strictMinMax": true,
"renderer": {
"type": "AxisRendererCircular",
"settings": {
"strokeOpacity": 0.1,
"minGridDistance": 30,
"startAngle": 95,
"endAngle": 175,
"stroke": {
"type": "Color",
"value": "#a367dc"
}
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"visible": false
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"visible": true,
"strokeOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#a367dc"
}
}
}
}
}
}
}
}
}
},
{
"axis-3": {
"type": "ValueAxis",
"settings": {
"maxDeviation": 0,
"min": 0,
"max": 100,
"strictMinMax": true,
"renderer": {
"type": "AxisRendererCircular",
"settings": {
"strokeOpacity": 0.1,
"minGridDistance": 30,
"startAngle": 185,
"endAngle": 265,
"stroke": {
"type": "Color",
"value": "#dc67ce"
}
},
"properties": {
"grid": {
"properties": {
"template": {
"settings": {
"visible": false
}
}
}
},
"ticks": {
"properties": {
"template": {
"settings": {
"visible": true,
"strokeOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#dc67ce"
}
}
}
}
}
}
}
}
}
},
{
"axisRange-0": {
"axis": "#axis-0",
"settings": {
"value": 0,
"endValue": 100,
"tick": {
"type": "AxisTick",
"settings": {
"visible": false
}
},
"axisFill": {
"type": "Slice",
"settings": {
"strokeWidth": 1,
"visible": true,
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"fillOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#67b7dc"
},
"strokeOpacity": 0.8
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-1": {
"axis": "#axis-0",
"settings": {
"value": 76.3474657086455,
"bullet": {
"type": "AxisBullet",
"settings": {
"sprite": {
"type": "ClockHand",
"settings": {
"radius": {
"type": "Percent",
"value": 90
},
"innerRadius": {
"type": "Percent",
"value": 70
}
},
"properties": {
"hand": {
"settings": {
"fill": {
"type": "Color",
"value": "#67b7dc"
},
"fillOpacity": 0.9
}
},
"pin": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-2": {
"axis": "#axis-1",
"settings": {
"value": 0,
"endValue": 200,
"tick": {
"type": "AxisTick",
"settings": {
"visible": false
}
},
"axisFill": {
"type": "Slice",
"settings": {
"strokeWidth": 1,
"visible": true,
"fill": {
"type": "Color",
"value": "#6771dc"
},
"fillOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#6771dc"
},
"strokeOpacity": 0.8
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-3": {
"axis": "#axis-1",
"settings": {
"value": 187.02460151956893,
"bullet": {
"type": "AxisBullet",
"settings": {
"sprite": {
"type": "ClockHand",
"settings": {
"radius": {
"type": "Percent",
"value": 90
},
"innerRadius": {
"type": "Percent",
"value": 70
}
},
"properties": {
"hand": {
"settings": {
"fill": {
"type": "Color",
"value": "#6771dc"
},
"fillOpacity": 0.9
}
},
"pin": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-4": {
"axis": "#axis-2",
"settings": {
"value": 0,
"endValue": 20,
"tick": {
"type": "AxisTick",
"settings": {
"visible": false
}
},
"axisFill": {
"type": "Slice",
"settings": {
"strokeWidth": 1,
"visible": true,
"fill": {
"type": "Color",
"value": "#a367dc"
},
"fillOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#a367dc"
},
"strokeOpacity": 0.8
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-5": {
"axis": "#axis-2",
"settings": {
"value": 9.728440214480413,
"bullet": {
"type": "AxisBullet",
"settings": {
"sprite": {
"type": "ClockHand",
"settings": {
"radius": {
"type": "Percent",
"value": 90
},
"innerRadius": {
"type": "Percent",
"value": 70
}
},
"properties": {
"hand": {
"settings": {
"fill": {
"type": "Color",
"value": "#a367dc"
},
"fillOpacity": 0.9
}
},
"pin": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-6": {
"axis": "#axis-3",
"settings": {
"value": 0,
"endValue": 100,
"tick": {
"type": "AxisTick",
"settings": {
"visible": false
}
},
"axisFill": {
"type": "Slice",
"settings": {
"strokeWidth": 1,
"visible": true,
"fill": {
"type": "Color",
"value": "#dc67ce"
},
"fillOpacity": 0.8,
"stroke": {
"type": "Color",
"value": "#dc67ce"
},
"strokeOpacity": 0.8
}
}
},
"__parseLogic": "axisRange"
}
},
{
"axisRange-7": {
"axis": "#axis-3",
"settings": {
"value": 32.48451252934877,
"bullet": {
"type": "AxisBullet",
"settings": {
"sprite": {
"type": "ClockHand",
"settings": {
"radius": {
"type": "Percent",
"value": 90
},
"innerRadius": {
"type": "Percent",
"value": 70
}
},
"properties": {
"hand": {
"settings": {
"fill": {
"type": "Color",
"value": "#dc67ce"
},
"fillOpacity": 0.9
}
},
"pin": {
"settings": {
"forceHidden": true
}
}
}
}
}
}
},
"__parseLogic": "axisRange"
}
}
]
}