0

I have this map example here that I am running through Highmaps from Highcharts.

You can observe that when we have this setting below, countries like Romania, Bulgaria, Serbia are not showing their label because the country is too small for that zoom level. If you zoom-in enough, those small countries will become bigger and their label is displayed.

dataLabels: {               
    enabled: true,
    useHTML: false,
    format: '{point.name}'
}

If I change to useHTML: true, all country labels will show all the time, no matter what the zoom level is or how small the country is which causes the labels to overlap really bad like this.

Because of the project requirements, sticking with useHTML: true is a must, but is there anyway to achieve the auto-hiding of the labels in this situation?

Roco CTZ
  • 1,107
  • 1
  • 16
  • 31

1 Answers1

1

You could try to use formatter instead of format and show only labels that should be visible. labelrank of point might be helpful. A bit random example (but you will get the idea): http://jsfiddle.net/Lu3ec0Lv/2/

Changed part:

formatter: function () {
                        var ret = null,
                            chart = this.series.chart,
                            xExt = chart.xAxis[0].getExtremes();
                        if ((this.point.labelrank%2 + (xExt.max - xExt.min))%2) ret = this.point.name;
                        return ret;
                    }
Kacper Madej
  • 7,846
  • 22
  • 36
  • Thank you for the reply, Kacper. I can see it's working on your example, but I'm afraid I still can't get it going in my scenario. I have a USA map with almost 1000 city shapes and that "if" condition always returns a value because `this.point.labelrank%2` has a value all the time (I get undefined in few cases out of 1000). This means I always get the labels displayed. Is there any suggestions that I could try? Or is there anything that I can do to make the restriction more narrow? – Roco CTZ Dec 15 '14 at 02:44
  • If null is returned then no label is displayed. Alternatively you can do as Highcharts codes does - set opacity to 0 for currently invisible labels. You can define restrictions on your own. It seems reasonable to hide labels for smaller map shapes (and for this you might use point._maxX / _minX / _maxY / _minY) but it's up to you. – Kacper Madej Dec 15 '14 at 10:19
  • Hi Kacper, I am trying to hide labels for small shapes, but I can't achieve this. Is there any formula I can use for: `if (shape_width < label_width) {return null} ? – Roco CTZ Dec 15 '14 at 11:39
  • 1
    Width of shape can be calculated using (point._maxX - point._minX) and next it should be scaled by zoom (i.e. from axis extremes - [API](http://api.highcharts.com/highmaps#Axis.getExtreme)) to get pixel width. – Kacper Madej Dec 15 '14 at 12:17
  • So far I followed your advice and managed to extract the pixel size of the country width: chart.xAxis[0].toPixels(this.point._maxX - this.point._minX), but any chance you can tell me how to do this for the name label? Thanks a lot for all the info! – Roco CTZ Dec 15 '14 at 12:39
  • Suggested on [stackoverflow](http://stackoverflow.com/questions/2057682/determine-pixel-length-of-string-in-javascript-jquery) way is to 'Wrap text in a span and use jquery width()'. For better performance: since you know all texts from all labels you could process that data earlier (i.e. store in an array) and later use calculated values. – Kacper Madej Dec 15 '14 at 13:31
  • I've got one more problem now... If I get get the shape width and use toPixels() on it I get for e.g a value of 400. If I measure that shape, it has a width of only 150px. Do you know why I get different values? – Roco CTZ Dec 16 '14 at 01:06
  • You should perform toPixels on max and on min and next deduct calculated values. Example: http://jsfiddle.net/pq2a4xn7/1/ – Kacper Madej Dec 16 '14 at 12:32
  • Thank you for all the support, I managed to do it. The thing that gave me trouble was that I first needed to convert maxX and minX to pixels before doing the substraction. – Roco CTZ Dec 17 '14 at 01:31