Remi Sture Remi Sture - 3 months ago 91
CSS Question

How to accomplish responsive texts in Highcharts gauges?

I've built a speedometer looking chart with Highcharts, combining the gauge and pie chart types. Inside the chart, I have texts in different sizes, optimized for a 250x250 px size.

What I want to accomplish is to maintain the font-size/graph-container ratio whenever the chart is resized. Basically have the same appearance no matter the size of the container.

I now have a pixel based font-size on the div containing the chart (typically the base font size of my project), and 1em on the chart itself (.highcharts-data-labels). Inside that are my custom texts, marked with css classes (.gauge-value, .gauge-text, .gauge-unit), which I have tried to give reasonable em values.

What is the best approach to accomplish this?

JSFiddle with demo

JS

$(function() {
var settings = {
gaugeMinValue: 0,
gaugeMaxValue: 8000,
gaugeStartValue: 3000,
gaugeStartAngle: -160,
gaugeEndAngle: 160,
gaugeUpdateInterval: 500 // ms
};

$('#gauge1').highcharts({
tooltip: {
enabled: false
},
chart: {
type: 'gauge',
backgroundColor: 'rgba(255, 255, 255, 0)',
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false,
spacing: [5, 30, 5, 30],
style: {
fontSize: '1em'
}
},

title: false,

pane: {
startAngle: settings.gaugeStartAngle,
endAngle: settings.gaugeEndAngle
},

plotOptions: {
gauge: {
dial: {
radius: 0
},
pivot: {
radius: 0
},
dataLabels: {
borderWidth: 0,
padding: 0,
verticalAlign: 'middle',
style: false,
formatter: function() {
var output = '<div class="gauge-data">';
output += '<span class="gauge-value">' + this.y + '</span>';
output += '<span class="gauge-text">Engine LOAD</span>';
output += '<span class="gauge-unit">KW</span>';
output += '</div>';

return output;
},
useHTML: true
}
},
pie: {
dataLabels: {
enabled: true,
distance: -10,
style: false
},
startAngle: settings.gaugeStartAngle,
endAngle: settings.gaugeEndAngle,
center: ['50%', '50%'],
states: {
hover: {
enabled: false
}
}
}
},

// the value axis
yAxis: {
offset: 0,
min: settings.gaugeMinValue,
max: settings.gaugeMaxValue,

title: false,

minorTickWidth: 0,

tickPixelInterval: 30,
tickWidth: 2,
tickPosition: 'outside',
tickLength: 14,
tickColor: '#ccc',
lineColor: '#ccc',
labels: {
distance: 28,
rotation: "0",
step: 2,
},

plotBands: [{
thickness: 10,
outerRadius: "112%",
from: 0,
to: 2500,
color: '#FB8585' // red
}, {
thickness: 10,
outerRadius: "112%",
from: 2500,
to: 5500,
color: '#F9E7AE' // yellow,
}, {
thickness: 10,
outerRadius: "112%",
from: 5500,
to: 8000,
color: '#83DAD9' // green
}]
},

series: [{
type: 'gauge',
data: [settings.gaugeStartValue],
}, {
type: 'pie',
innerSize: '87%',
data: [{
y: settings.gaugeStartValue,
name: "",
color: "#0bbeba"
}, {
y: settings.gaugeMaxValue - settings.gaugeStartValue,
name: '',
color: "#666666"
}]
}],

navigation: {
buttonOptions: {
enabled: false
}
},

credits: false
});
});


CSS

.container {
width: 50%;
margin: 0 auto;
font-size: 16px;
}

.gauge {
width: 100%;
max-width: 350px;
max-height: 350px;
min-width: 250px;
min-height: 250px;
padding: 0;
border: 1px solid #666;
background: #F8F8F8;
}

.gauge-data {
text-align: center;
color: #666;
display: block;
}

.gauge-data > * {
display: block;
}

.gauge-value {
font-size: 3em;
}

.gauge-text {
font-size: 1.0em;
font-weigt: normal;
margin-top: 10px;
}

.gauge-unit {
margin-top: 5px;
font-size: .9em;
}


Image 1: This is the optimal view

Optimized

Image 2: Font size is not scaling along with the graph as the container size increases

Font size is not scaling along with the graph

Answer

You could update dataLabel for gauge series and use inline CSS to set font-size per each text line based on current chart width.

Demo: https://jsfiddle.net/sxkz9q32/

Relevant part of code:

  var options = {
    tooltip: {
      enabled: false
    },
    chart: {
      type: 'gauge',
      backgroundColor: 'rgba(255, 255, 255, 0)',
      plotBackgroundColor: null,
      plotBackgroundImage: null,
      plotBorderWidth: 0,
      plotShadow: false,
      spacing: [5, 30, 5, 30],
      style: {
        fontSize: '1em'
      },
      events: {
        redraw: function() {
          var chart = this;
          if (chart.lastWidth !== chart.plotWidth) {
            chart.lastWidth = chart.plotWidth;
            chart.series[0].update({ //apply changes to center the text
              dataLabels: {
                formatter: function() {
                  var output = '<div class="gauge-data">';
                  output += '<span class="gauge-value" style="font-size: ' + chart.plotWidth / 66 + 'em;">' + this.y + '</span>';
                  output += '<span class="gauge-text" style="font-size: ' + chart.plotWidth / 190 + 'em;">Engine LOAD</span>';
                  output += '<span class="gauge-unit" style="font-size: ' + chart.plotWidth / 211 + 'em;">KW</span>';
                  output += '</div>';

                  return output;
                }
              }
            }); 
          }
        }
      }
    },

I have used values based on width that were looking fine for me, but could use your own calculations.