In my searches for linear gauge control I didn't find any viable solution.
So I've created one based on D3 stacked bar graph.
See JSFiddle for implementation details
The final result will be something like this:
The Html will be pretty simple, only the container where we will put all the drawing
<
div id="linearGaugeContainer"></
div>
I'm using SVG gradients definition in this sample
<!--define svg gradients to be used in java script. make sure the svg tag takes no room on your page=> width and height = 0px-->
<svg style="height: 0px; width: 0px;" xmlns="http://www.w3.org/2000/svg">
<defs>
<lineargradient id="NORMAL_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#C1DC99" stop-opacity="1">
<stop offset="100%" stop-color="#669900" stop-opacity="1">
</stop></stop></lineargradient>
<lineargradient id="WARNING_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#84C6F6" stop-opacity="1">
<stop offset="100%" stop-color="#6FA7CF" stop-opacity="1">
</stop></stop></lineargradient>
<lineargradient id="MINOR_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#FFE537" stop-opacity="1">
<stop offset="100%" stop-color="#F9C328" stop-opacity="1">
</stop></stop></lineargradient>
<lineargradient id="MAJOR_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#FF9900" stop-opacity="1">
<stop offset="100%" stop-color="#FF6700" stop-opacity="1">
</stop></stop></lineargradient>
<lineargradient id="CRITICAL_COLOR" spreadmethod="pad" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#E70030" stop-opacity="1">
<stop offset="100%" stop-color="#B30020" stop-opacity="1">
</stop></stop></lineargradient>
</defs>
</svg>
The javascript code is a bit long, just follow the comments within the code:
//Linear gauge
//The way to implement it would be:
// - To take a stacked bar graph as a basis
// - Ignore all the graph related attributes
// (like: axis, ticks and so on)
// - Define a single set of data
// - Swap the x and y axis values
var margins = {
top: 12,
left: 48,
right: 24,
bottom: 24
},
width = 700 - margins.left - margins.right
height = 15,
dataset = [{
data: [{
barId: '1', // we assign some random value, the most important to keep it same for all the entries
percent: 0.1, // percentage that we want a specific value to occupy as a part of the gauge: values betwee 0-1
severity: 'NORMAL_COLOR'// color id that we'll used to reference gradient value
}]
}, {
data: [{
barId: '1',
percent: 0.4,
severity: 'WARNING_COLOR'
}]
}, {
data: [{
barId: '1',
percent: 0.22,
severity: 'MINOR_COLOR'
}]
}, {
data: [{
barId: '1',
percent: 0.2,
severity: 'MAJOR_COLOR'
}]
}, {
data: [{
barId: '1',
percent: 0.08,
severity: 'CRITICAL_COLOR'
}]
}],
dataset = dataset.map(function (d) {
return d.data.map(function (o, i) {
// Structure it so that your numeric
// axis (the stacked amount) is y
return {
y: o.percent,
x: o.barId,
severity:o.severity
};
});
}),
stack = d3.layout.stack();
stack(dataset);
var dataset = dataset.map(function (group) {
return group.map(function (d) {
// Invert the x and y values, and y0 becomes x0
return {
x: d.y,
y: d.x,
x0: d.y0,
severity:d.severity
};
});
}),
svg = d3.select('#linearGaugeContainer')
.append('svg')
.attr('width', width + margins.left + margins.right)
.attr('height', height + margins.top + margins.bottom)
.append('g')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
xMax = d3.max(dataset, function (group) {
return d3.max(group, function (d) {
return d.x + d.x0;
});
}),
xScale = d3.scale.linear()
.domain([0, xMax])
.range([0, width]),
yValue = dataset[0].map(function (d) {
return d.y;
}),
yScale = d3.scale.ordinal()
.domain(yValue)
.rangeRoundBands([0, height], .1),
// this color funciton referencing the linearGradient defind in the HTML part by id
color = function (index) {
console.log(dataset[index][0])
return "url(#" + dataset[index][0].severity + ")";
},
groups = svg.selectAll('g')
.data(dataset)
.enter()
.append('g')
.style('fill', function (d, i) {
return color(i);
});
var rects = groups.selectAll('rect')
.data(function (d) {
return d;
}).enter();
rects.append('rect')
.attr('x', function (d) {
return xScale(d.x0);
})
.attr('y', function (d, i) {
return yScale(d.y);
})
.attr('height', function (d) {
return yScale.rangeBand();
})
.attr('width', function (d) {
return xScale(d.x);
});
// locate a label with percentage above each section of the gauge
rects.append("text")
.text(function(d,i) { return (d.x * 100) + '%' })
.attr("x", function(d) { return xScale(d.x0); })
.style("stroke", '#000000')